Railway Operation Simulator  v2.23.2
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 /*
2  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
3  sometimes been overtaken by changes and not updated
4  Comments in .h files are believed to be accurate and up to date
5 
6  This is a source code file for "railway.exe", a railway operation
7  simulator, written originally in Borland C++ Builder 4 Professional with
8  later updates in Embarcadero C++Builder.
9  Copyright (C) 2010 Albert Ball [original development]
10 
11  This program is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24 // ---------------------------------------------------------------------------
25 #include <Classes.hpp>
26 #include <Controls.hpp>
27 #include <StdCtrls.hpp>
28 #include <Forms.hpp>
29 #include <Buttons.hpp>
30 #include <ExtCtrls.hpp>
31 #include <Menus.hpp>
32 #include <Dialogs.hpp>
33 #include <Graphics.hpp>
34 #include <ComCtrls.hpp>
35 #include <fstream>
36 #include <vector>
37 #include <algorithm> //for std::find
38 #include <vcl.h>
39 #include <windows.h>
40 #pragma hdrstop
41 
42 #include "TrackUnit.h"
43 #include "TrainUnit.h"
44 #include "GraphicUnit.h"
45 //#include "DisplayUnit.h" included in TrackUnit.h
46 #include "TextUnit.h"
47 #include "PerfLogUnit.h"
48 #include "Utilities.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  //deal with TSRs
226  if((TrackType == Simple) && Failed) //added at v2.13.0
227  {
228  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
229  }
230  Utilities->CallLogPop(1332);
231 }
232 
233 // ---------------------------------------------------------------------------
234 
235 AnsiString TTrackElement::LogTrack(int Caller) const
236 // for debugging when passes as a call parameter
237 {
238  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
239  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
240 
241  return(LogString);
242 }
243 
244 // ---------------------------------------------------------------------------
245 
247  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
248  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
249  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
250  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
251  {
252  Failed = false; //added at v2.13.0
253  for(int x = 0; x < 4; x++)
254  {
255  ConnLinkPos[x] = -1;
256  Conn[x] = -1;
257  }
258  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
259  {
262  }
263  }
264 
265 // ---------------------------------------------------------------------------
266 
267 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
268 {
269  if(lower.second < higher.second)
270  {
271  return(true);
272  }
273  else if(lower.second > higher.second)
274  {
275  return(false);
276  }
277  else if(lower.second == higher.second)
278  {
279  if(lower.first < higher.first)
280  {
281  return(true);
282  }
283  }
284  return(false);
285 }
286 
287 // ---------------------------------------------------------------------------
288 // PrefDirElement Functions
289 // ---------------------------------------------------------------------------
290 
291 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
292  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
293  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
294 {
295  if(!EntryExitNumber())
296  {
297  throw Exception("EXNumber failure in TPrefDirElement constructor");
298  }
301 }
302 
303 // ---------------------------------------------------------------------------
304 
305 AnsiString TPrefDirElement::LogPrefDir() const
306 // for debugging when passed as a call parameter
307 {
308  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
309  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
310  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
312 
313 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
314  return(LogString);
315 }
316 
317 // ---------------------------------------------------------------------------
318 
319 bool TPrefDirElement::EntryExitNumber() // true for valid number
320 /*
321  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
322  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
323  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
324  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
325  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
326  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
327  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
328  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
329  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
330 */
331 
332 {
333  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
334  int EXArray[16][2] =
335  {{4, 6}, {2, 8}, // horizontal & vertical
336  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
337  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
338  {1, 9}, {3, 7}}; // forward & reverse diagonals
339 
340  int EXNum = -1;
341  int Entry, Exit;
342 
343  if(ELink > -1)
344  {
345  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
346  }
347  else if(Link[2] == -1)
348  {
349  Entry = Link[0];
350  }
351  else
352  {
353  Utilities->CallLogPop(122);
354  return(false);
355  }
356  if(XLink > -1)
357  {
358  Exit = XLink;
359  }
360  else if(Link[2] == -1)
361  {
362  Exit = Link[1];
363  }
364  else
365  {
366  Utilities->CallLogPop(123);
367  return(false);
368  }
369  for(int x = 0; x < 16; x++)
370  {
371  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
372  {
373  EXNum = x;
374  }
375  }
376  if(EXNum == -1)
377  {
378  Utilities->CallLogPop(124);
379  return(false);
380  }
381  int BrNum = -1;
382 
383 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
384  the graphic for each of which is different because of the shape of the overbridge. The basic
385  entry/exit value is computed above, and this used to select only from elements with that entry/exit
386  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
387  int BrEXArray[24][2] = {
388  {4,6},{2,8},{1,9},{3,7},
389  {1,9},{3,7},{1,9},{3,7},
390  {2,8},{4,6},{2,8},{4,6}
391 */
392 
393  if(TrackType == Bridge)
394  {
395  if(EXNum == 1)
396  {
397  if(SpeedTag == 49)
398  {
399  BrNum = 1 + 16;
400  }
401  else if(SpeedTag == 54)
402  {
403  BrNum = 8 + 16;
404  }
405  else if(SpeedTag == 55)
406  {
407  BrNum = 10 + 16;
408  }
409  }
410  else if(EXNum == 0)
411  {
412  if(SpeedTag == 48)
413  {
414  BrNum = 0 + 16;
415  }
416  else if(SpeedTag == 58)
417  {
418  BrNum = 11 + 16;
419  }
420  else if(SpeedTag == 59)
421  {
422  BrNum = 9 + 16;
423  }
424  }
425  else if(EXNum == 14)
426  {
427  if(SpeedTag == 50)
428  {
429  BrNum = 2 + 16;
430  }
431  else if(SpeedTag == 52)
432  {
433  BrNum = 4 + 16;
434  }
435  else if(SpeedTag == 57)
436  {
437  BrNum = 6 + 16;
438  }
439  }
440  else if(EXNum == 15)
441  {
442  if(SpeedTag == 51)
443  {
444  BrNum = 3 + 16;
445  }
446  else if(SpeedTag == 53)
447  {
448  BrNum = 7 + 16;
449  }
450  else if(SpeedTag == 56)
451  {
452  BrNum = 5 + 16;
453  }
454  }
455  }
456  if(BrNum == -1)
457  {
458  EXNumber = EXNum;
459  }
460  else
461  {
462  EXNumber = BrNum;
463  }
464  Utilities->CallLogPop(125);
465  return(true);
466 }
467 
468 // ---------------------------------------------------------------------------
469 
471 /*
472  This is the basic track graphic for use in plotting the original graphic during route flashing.
473  Enter with all set apart from EXGraphic & EntryDirectionGraphic
474 */
475 {
476  if(SpeedTag == 64)
477  {
478  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
479 
480  }
481  if(SpeedTag == 65)
482  {
483  return(RailGraphics->LinkGraphicsPtr[17]);
484  }
485  if(SpeedTag == 66)
486  {
487  return(RailGraphics->LinkGraphicsPtr[18]);
488  }
489  if(SpeedTag == 67)
490  {
491  return(RailGraphics->LinkGraphicsPtr[19]);
492  }
493  if(SpeedTag == 80)
494  {
495  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
496 
497  }
498  if(SpeedTag == 81)
499  {
500  return(RailGraphics->LinkGraphicsPtr[21]);
501  }
502  if(SpeedTag == 82)
503  {
504  return(RailGraphics->LinkGraphicsPtr[22]);
505  }
506  if(SpeedTag == 83)
507  {
508  return(RailGraphics->LinkGraphicsPtr[23]);
509  }
510  if(SpeedTag == 84)
511  {
512  return(RailGraphics->LinkGraphicsPtr[24]);
513  }
514  if(SpeedTag == 85)
515  {
516  return(RailGraphics->LinkGraphicsPtr[25]);
517  }
518  if(SpeedTag == 86)
519  {
520  return(RailGraphics->LinkGraphicsPtr[26]);
521  }
522  if(SpeedTag == 87)
523  {
524  return(RailGraphics->LinkGraphicsPtr[27]);
525  }
526  if(SpeedTag == 129)
527  {
528  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
529 
530  }
531  if(SpeedTag == 130)
532  {
533  return(RailGraphics->LinkGraphicsPtr[29]);
534  }
535  if(XLinkPos == -1) // not set, could be first element or last element = leading point
536  {
537 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
538 // Points & don't want to display these)
539  if(Link[2] != -1)
540  {
541  return(0); // i.e. complex element, don't display
542  }
543  else
544  {
545  if(!EntryExitNumber())
546  {
547  throw Exception("Error in EntryExitNumber 4");
548  }
549  else
550  {
552  }
553  }
554  }
555  if(EXNumber > 15) // underbridge
556  {
557  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
558  }
559  else
560  {
562  }
563 }
564 
565 // ---------------------------------------------------------------------------
566 
568 /*
569  As above but for PrefDir graphics.
570 */
571 {
572  if(SpeedTag == 64)
573  {
574  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
575 
576  }
577  if(SpeedTag == 65)
578  {
580  }
581  if(SpeedTag == 66)
582  {
584  }
585  if(SpeedTag == 67)
586  {
588  }
589  if(SpeedTag == 80)
590  {
591  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
592 
593  }
594  if(SpeedTag == 81)
595  {
597  }
598  if(SpeedTag == 82)
599  {
601  }
602  if(SpeedTag == 83)
603  {
605  }
606  if(SpeedTag == 84)
607  {
609  }
610  if(SpeedTag == 85)
611  {
613  }
614  if(SpeedTag == 86)
615  {
617  }
618  if(SpeedTag == 87)
619  {
621  }
622  if(SpeedTag == 129)
623  {
624  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
625 
626  }
627  if(SpeedTag == 130)
628  {
630  }
631  if(XLinkPos == -1) // not set, could be first element or last element = leading point
632  {
633 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
634  if(Link[2] != -1)
635  {
636  return(0); // i.e. complex element, don't display
637  }
638  else
639  {
640  if(!EntryExitNumber())
641  {
642  throw Exception("Error in EntryExitNumber 5");
643  }
644  else
645  {
647  }
648  }
649  }
650  if(EXNumber > 15) // underbridge
651  {
653  }
654  else
655  {
657  }
658 }
659 
660 // ---------------------------------------------------------------------------
661 
662 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
663 /*
664  As above but for route graphics.
665 */
666 {
667  if(!AutoSigsFlag && !PrefDirRoute)
668  {
669  if(SpeedTag == 64)
670  {
671  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
672  }
673  if(SpeedTag == 65)
674  {
676  }
677  if(SpeedTag == 66)
678  {
680  }
681  if(SpeedTag == 67)
682  {
684  }
685  if(SpeedTag == 80)
686  {
687  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
688  }
689  if(SpeedTag == 81)
690  {
692  }
693  if(SpeedTag == 82)
694  {
696  }
697  if(SpeedTag == 83)
698  {
700  }
701  if(SpeedTag == 84)
702  {
704  }
705  if(SpeedTag == 85)
706  {
708  }
709  if(SpeedTag == 86)
710  {
712  }
713  if(SpeedTag == 87)
714  {
716  }
717  if(SpeedTag == 129)
718  {
719  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
720  }
721  if(SpeedTag == 130)
722  {
724  }
725  if(XLinkPos == -1) // not set, could be first element or last element = leading point
726  {
727  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
728  if(Link[2] != -1)
729  {
730  return(0); // i.e. complex element, don't display
731  }
732  else
733  {
734  if(!EntryExitNumber())
735  {
736  throw Exception("Error in EntryExitNumber 6");
737  }
738  else
739  {
741  }
742  }
743  }
744  if(EXNumber > 15) // underbridge
745  {
747  }
748  else
749  {
751  }
752  }
753 
754  else if(!AutoSigsFlag && PrefDirRoute)
755  {
756  if(SpeedTag == 64)
757  {
758  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
759  }
760  if(SpeedTag == 65)
761  {
763  }
764  if(SpeedTag == 66)
765  {
767  }
768  if(SpeedTag == 67)
769  {
771  }
772  if(SpeedTag == 80)
773  {
774  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
775  }
776  if(SpeedTag == 81)
777  {
779  }
780  if(SpeedTag == 82)
781  {
783  }
784  if(SpeedTag == 83)
785  {
787  }
788  if(SpeedTag == 84)
789  {
791  }
792  if(SpeedTag == 85)
793  {
795  }
796  if(SpeedTag == 86)
797  {
799  }
800  if(SpeedTag == 87)
801  {
803  }
804  if(SpeedTag == 129)
805  {
806  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846  }
847  if(SpeedTag == 65)
848  {
850  }
851  if(SpeedTag == 66)
852  {
854  }
855  if(SpeedTag == 67)
856  {
858  }
859  if(SpeedTag == 80)
860  {
861  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
862 
863  }
864  if(SpeedTag == 81)
865  {
867  }
868  if(SpeedTag == 82)
869  {
871  }
872  if(SpeedTag == 83)
873  {
875  }
876  if(SpeedTag == 84)
877  {
879  }
880  if(SpeedTag == 85)
881  {
883  }
884  if(SpeedTag == 86)
885  {
887  }
888  if(SpeedTag == 87)
889  {
891  }
892  if(SpeedTag == 129)
893  {
894  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
895 
896  }
897  if(SpeedTag == 130)
898  {
900  }
901  if(XLinkPos == -1) // not set, could be first element or last element = leading point
902  {
903  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
904  if(Link[2] != -1)
905  {
906  return(0); // i.e. complex element, don't display
907  }
908  else
909  {
910  if(!EntryExitNumber())
911  {
912  throw Exception("Error in EntryExitNumber 11");
913  }
914  else
915  {
917  }
918  }
919  }
920  if(EXNumber > 15) // underbridge
921  {
923  }
924  else
925  {
927  }
928  }
929 }
930 
931 // ---------------------------------------------------------------------------
932 
934 /*
935  As above but for route flashing graphics. (Disused - now combined with above)
936 */
937 {
938  if(SpeedTag == 64)
939  {
940  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
941 
942  }
943  if(SpeedTag == 65)
944  {
946  }
947  if(SpeedTag == 66)
948  {
950  }
951  if(SpeedTag == 67)
952  {
954  }
955  if(SpeedTag == 80)
956  {
957  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
958 
959  }
960  if(SpeedTag == 81)
961  {
963  }
964  if(SpeedTag == 82)
965  {
967  }
968  if(SpeedTag == 83)
969  {
971  }
972  if(SpeedTag == 84)
973  {
975  }
976  if(SpeedTag == 85)
977  {
979  }
980  if(SpeedTag == 86)
981  {
983  }
984  if(SpeedTag == 87)
985  {
987  }
988  if(SpeedTag == 129)
989  {
990  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
991 
992  }
993  if(SpeedTag == 130)
994  {
996  }
997  if(XLinkPos == -1) // not set, could be first element or last element = leading point
998  {
999 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1000  if(Link[2] != -1)
1001  {
1002  return(0); // i.e. complex element, don't display
1003  }
1004  else
1005  {
1006  if(!EntryExitNumber())
1007  {
1008  throw Exception("Error in EntryExitNumber 7");
1009  }
1010  else
1011  {
1013  }
1014  }
1015  }
1016  if(EXNumber > 15) // underbridge
1017  {
1019  }
1020  else
1021  {
1023  }
1024 }
1025 
1026 // ---------------------------------------------------------------------------
1027 
1029 /*
1030  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1031 */
1032 {
1033  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1034  {
1036  }
1037  else
1038  {
1039  throw Exception("Error in EntryExitNumber 8");
1040  }
1041 }
1042 
1043 // ---------------------------------------------------------------------------
1044 
1045 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1046 /*
1047  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1048 */
1049 {
1050  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1051  {
1052  if(!AutoSigsFlag && !PrefDirRoute)
1053  {
1055  }
1056  else if(!AutoSigsFlag && PrefDirRoute)
1057  {
1059  }
1060  else
1061  {
1063  }
1064  }
1065  else
1066  {
1067  throw Exception("Error in EntryExitNumber 9");
1068  }
1069 }
1070 
1071 // ---------------------------------------------------------------------------
1072 
1074 /*
1075  Set == operator when TrackVectorPosition, ELink & XLink all same
1076 */
1077 {
1078  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1079  {
1080  return(true);
1081  }
1082  else
1083  {
1084  return(false);
1085  }
1086 }
1087 
1088 // ---------------------------------------------------------------------------
1089 
1091 /*
1092  Set != operator when any of TrackVectorPosition, ELink or XLink different
1093 */
1094 {
1095  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1096  {
1097  return(false);
1098  }
1099  else
1100  {
1101  return(true);
1102  }
1103 }
1104 
1105 // ---------------------------------------------------------------------------
1106 
1107 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1108 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1109  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1110  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1111  {
1112  Utilities->CallLogPop(2566);
1113  return(1);
1114  }
1115  if(GetRouteGraphicPtr(0,1) == EXG)
1116  {
1117  Utilities->CallLogPop(2567);
1118  return(2);
1119  }
1120  if(GetRouteGraphicPtr(1,0) == EXG)
1121  {
1122  Utilities->CallLogPop(2568);
1123  return(3);
1124  }
1125  if(GetRouteGraphicPtr(1,1) == EXG)
1126  {
1127  Utilities->CallLogPop(2569);
1128  return(3);
1129  }
1130  Utilities->CallLogPop(2570);
1131  return(0);
1132 }
1133 
1134 // ---------------------------------------------------------------------------
1135 // Track functions
1136 // ---------------------------------------------------------------------------
1137 
1138 // ---------------------------------------------------------------------------
1139 
1141 {
1142  TypeOfRoute = 0;
1143  ReducedTimePenalty = false;
1144  BarrierState = Up;
1145  ChangeDuration = 0.0;
1146  BaseElementSpeedTag = 1;
1147  HLoc = 0;
1148  VLoc = 0;
1149  StartTime = TDateTime(0);
1150 }
1151 
1152 // ---------------------------------------------------------------------------
1153 
1155 {
1156 // CurrentSpeedButtonTag = 0; //not assigned yet
1157 
1158  HLocMin = 2000000000;
1159  VLocMin = 2000000000;
1160  HLocMax = -2000000000;
1161  VLocMax = -2000000000;
1162  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1163  CopyFlag = false; // only true for copying, so names aren't copied
1164  AnsiString NL = '\n';
1165 
1166  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1167  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1168  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1169  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1170 
1175  LengthHeatMapFlag = false;
1176  SpeedHeatMapFlag = false;
1177 
1178  int InternalLinkCheckArray[9][2] =
1179  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1180 
1181 /* array of valid link values for 'old' location and 'new' location, where
1182  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1183 
1184  for(int x = 0; x < 9; x++)
1185  {
1186  for(int y = 0; y < 2; y++)
1187  {
1188  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1189  }
1190  }
1191 
1192 // Platform and default track element values
1193  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1194 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1195  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1196  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1197  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1198  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1199  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1200  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1201  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1202  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1203  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1204  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1205 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1206 
1207  int HVArray[10][2] =
1208  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1209 
1210  for(int x = 0; x < 10; x++)
1211  {
1212  for(int y = 0; y < 2; y++)
1213  {
1214  LinkHVArray[x][y] = HVArray[x][y];
1215  }
1216  }
1217  TrackFinished = false;
1218 // DistancesSet = false;
1219 
1220  TSigElement TempSigTable[40] = // original four aspect
1221  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1222  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1223 
1224  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1225  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1226 
1229 
1230  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1231  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1232 
1233  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1234  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1235  {75, 4, RailGraphics->gl75}};
1236 
1237  for(int x = 0; x < 40; x++)
1238  {
1239  SigTable[x] = TempSigTable[x];
1240  }
1241 
1242  TSigElement TempSigTableThreeAspect[40] =
1243  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1244  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1245 
1246  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1247  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1248 
1249  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1250  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1251 
1252  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1253  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1254 
1255  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1256  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1257  {75, 4, RailGraphics->gl75}};
1258 
1259  for(int x = 0; x < 40; x++)
1260  {
1261  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1262  }
1263 
1264  TSigElement TempSigTableTwoAspect[40] =
1265  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1266  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1267 
1268  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1269  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1270 
1271  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1272  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1273 
1274  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1275  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1276 
1277  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1278  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1279  {75, 4, RailGraphics->gl75}};
1280 
1281  for(int x = 0; x < 40; x++)
1282  {
1283  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1284  }
1285 
1286  TSigElement TempSigTableGroundSignal[40] =
1290 
1294 
1298 
1302 
1303  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1306 
1307  for(int x = 0; x < 40; x++)
1308  {
1309  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1310  }
1311 
1312  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1313  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1314  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1315 
1316  for(int x = 0; x < 8; x++)
1317  {
1318  FailedSigTable[x] = TempFailedSigTable[x];
1319  }
1320 
1321  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1322  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1323  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1324 
1325  for(int x = 0; x < 8; x++)
1326  {
1327  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1328  }
1329 
1330 /*
1331  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1332  a single location. These are as follows:-
1333  Directly Adjacent = up, down, left or right - NOT diagonal.
1334  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1335  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1336  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1337 
1338  //t 76
1339  //b 77
1340  //l 78
1341  //r 79
1342  //c 96
1343  //v fb 129
1344  //h fb 130
1345  //v underpass 145
1346  //h underpass 146
1347  //n 131
1348 */
1349 
1350  int Tag76[25][3] =
1351  {{-1, 0, 96}, // c top plat
1352  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1353  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1354  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1355  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1356  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1357  {0, 0, 129}, {0, -1, 145}, // v up
1358  {0, 0, 145}};
1359 
1360  for(int x = 0; x < 25; x++)
1361  {
1362  for(int y = 0; y < 3; y++)
1363  {
1364  Tag76Array[x][y] = Tag76[x][y];
1365  }
1366  }
1367 
1368  int Tag77[25][3] =
1369  {{-1, 0, 96}, // c bot plat
1370  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1371  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1372  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1373  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1374  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1375  {0, 0, 129}, {0, 1, 145}, // v up
1376  {0, 0, 145}};
1377 
1378  for(int x = 0; x < 25; x++)
1379  {
1380  for(int y = 0; y < 3; y++)
1381  {
1382  Tag77Array[x][y] = Tag77[x][y];
1383  }
1384  }
1385 
1386  int Tag78[25][3] =
1387  {{-1, 0, 96}, // c left plat
1388  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1389  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1390  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1391  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1392  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1393  {0, 0, 130}, {-1, 0, 146}, // h up
1394  {0, 0, 146}};
1395 
1396  for(int x = 0; x < 25; x++)
1397  {
1398  for(int y = 0; y < 3; y++)
1399  {
1400  Tag78Array[x][y] = Tag78[x][y];
1401  }
1402  }
1403 
1404  int Tag79[25][3] =
1405  {{-1, 0, 96}, // c right plat
1406  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1407  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1408  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1409  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1410  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1411  {0, 0, 130}, {1, 0, 146}, // h up
1412  {0, 0, 146}};
1413 
1414  for(int x = 0; x < 25; x++)
1415  {
1416  for(int y = 0; y < 3; y++)
1417  {
1418  Tag79Array[x][y] = Tag79[x][y];
1419  }
1420  }
1421 
1422  int Tag96[28][3] =
1423  {{-1, 0, 96}, // c //concourse
1424  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1425  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1426  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1427  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1428  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1429  {0, -1, 129}, {1, 0, 130}, // h fb
1430  {-1, 0, 130}, {0, 1, 145}, // v up
1431  {0, -1, 145}, {1, 0, 146}, // h up
1432  {-1, 0, 146}};
1433 
1434  for(int x = 0; x < 28; x++)
1435  {
1436  for(int y = 0; y < 3; y++)
1437  {
1438  Tag96Array[x][y] = Tag96[x][y];
1439  }
1440  }
1441 
1442  int Tag129[8][3] = // vert fb
1443  {{0, -1, 96}, // c
1444  {0, -1, 77}, // b
1445  {0, -1, 129}, // v fb
1446 
1447  {0, 1, 96}, // c
1448  {0, 1, 76}, // t
1449  {0, 1, 129}, // v fb
1450 
1451  {0, 0, 76}, // t
1452  {0, 0, 77}}; // b
1453 
1454  for(int x = 0; x < 8; x++)
1455  {
1456  for(int y = 0; y < 3; y++)
1457  {
1458  Tag129Array[x][y] = Tag129[x][y];
1459  }
1460  }
1461 
1462  int Tag145[8][3] = // vert up
1463  {{0, -1, 96}, // c
1464  {0, -1, 77}, // b
1465  {0, -1, 145}, // v fb
1466 
1467  {0, 1, 96}, // c
1468  {0, 1, 76}, // t
1469  {0, 1, 145}, // v fb
1470 
1471  {0, 0, 76}, // t
1472  {0, 0, 77}}; // b
1473 
1474  for(int x = 0; x < 8; x++)
1475  {
1476  for(int y = 0; y < 3; y++)
1477  {
1478  Tag145Array[x][y] = Tag145[x][y];
1479  }
1480  }
1481 
1482  int Tag130[8][3] = // hor fb
1483  {{-1, 0, 96}, // c
1484  {-1, 0, 79}, // r
1485  {-1, 0, 130}, // h fb
1486 
1487  {1, 0, 96}, // c
1488  {1, 0, 78}, // l
1489  {1, 0, 130}, // h fb
1490 
1491  {0, 0, 78}, // l
1492  {0, 0, 79}}; // r
1493 
1494  for(int x = 0; x < 8; x++)
1495  {
1496  for(int y = 0; y < 3; y++)
1497  {
1498  Tag130Array[x][y] = Tag130[x][y];
1499  }
1500  }
1501 
1502  int Tag146[8][3] = // hor up
1503  {{-1, 0, 96}, // c
1504  {-1, 0, 79}, // r
1505  {-1, 0, 146}, // h fb
1506 
1507  {1, 0, 96}, // c
1508  {1, 0, 78}, // l
1509  {1, 0, 146}, // h fb
1510 
1511  {0, 0, 78}, // l
1512  {0, 0, 79}}; // r
1513 
1514  for(int x = 0; x < 8; x++)
1515  {
1516  for(int y = 0; y < 3; y++)
1517  {
1518  Tag146Array[x][y] = Tag146[x][y];
1519  }
1520  }
1521 
1522  int Tag131[4][3] =
1523  {{-1, 0, 131}, // n
1524  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1525 
1526  for(int x = 0; x < 4; x++)
1527  {
1528  for(int y = 0; y < 3; y++)
1529  {
1530  Tag131Array[x][y] = Tag131[x][y];
1531  }
1532  }
1533 
1534  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1535  {
1536  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1537  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1538  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1539  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1540  140, 144, 145, 146
1541  };
1542 
1543  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1544  {
1545  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1546  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1547  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1548  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1549  141, 144, 145, 146
1550  };
1551 
1552  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1553  {
1554  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1555  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1556  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1557  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1558  141, 144, 146, 145
1559  };
1560 
1561  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1562  {
1563  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1564  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1565  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1566  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1567  140, 144, 146, 145
1568  };
1569 
1570  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1571  {
1572  FlipArray[x] = InternalFlipArray[x];
1573  MirrorArray[x] = InternalMirrorArray[x];
1574  RotRightArray[x] = InternalRotRightArray[x];
1575  RotLeftArray[x] = InternalRotLeftArray[x];
1576  }
1577 }
1578 
1579 // ---------------------------------------------------------------------------
1581 {
1582 // delete TrackVectorPtr;
1583 // delete FixedTrackArrayPtr;
1584  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1585 
1586  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1587  {
1588  delete UGMIt->second;
1589  UGMIt++;
1590  }
1591  delete GapFlashGreen;
1592  delete GapFlashRed;
1593  // all the rest are cleared by the relevant automatic destructors
1594 }
1595 
1596 // ---------------------------------------------------------------------------
1597 
1599 {
1600  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1601  {
1602 // loc 0 not used, set to bmSolidBgnd
1606 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1626  };
1627 
1628  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1629  {
1630 // loc 0 not used, set to smSolidBgnd
1634 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1653  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1654  };
1655 
1656 // track types
1657  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1658  {
1659  Erase, // 1 0
1660  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1661  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1662  Crossover, Crossover, // 2 15-16
1663  Unused, // 17 (was for text in earlier development) //1 17
1666  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1670  Platform, Platform, Platform, Platform, // 4 76-79
1673  Concourse, // 1 96
1676  Simple, Simple, Simple, Simple, // 4 125-128
1677  FootCrossing, FootCrossing, // 2 129-130
1678  NamedNonStationLocation, // 1 131
1679  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1680  Simple, Simple, Simple, Simple, // 4 140-143
1681  LevelCrossing, // 1 144
1682  FootCrossing, FootCrossing // 2 145 & 146
1683  };
1684 
1685 // links
1686  int Links[FirstUnusedSpeedTagNumber][4] =
1687  {{-1, -1, -1, -1}, // erase element
1688  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1689  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1690 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1691  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1692  {-1, -1, -1, -1}, // unused
1693  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1694  {2, 7, -1, -1}, // simple
1695  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1696 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1697 // (or right diverging if no straight)
1698  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1699  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1700  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1701  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1702  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1704  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1705  {-1, -1, -1, -1}, // Concourse
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1709  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1710  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1711  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1712  {-1, -1, -1, -1}, // NamedNonStationLocation
1713  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1714 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1715  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1716  {-1, -1, -1, -1}, // level crossing
1717  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1718  };
1719 
1721  {{NotSet, NotSet, NotSet, NotSet}, // unused
1725  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1727  {NotSet, NotSet, NotSet, NotSet}, // unused
1731  {Connection, Connection, NotSet, NotSet}, // simple
1735  {Lead, Trail, Lead, Trail}, // points
1737  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1745  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1751  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1760  {Connection, Connection, NotSet, NotSet}, // Arrows
1762  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1764  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1766  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1767  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1768  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1769  };
1770 
1771  for(int x = 0; x < 17; x++)
1772  {
1773  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1774  }
1775  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1776 // 17 was the old text value so don't want any graphics (now disused)
1777  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1778  {
1779  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1780  }
1781 }
1782 
1783 // ---------------------------------------------------------------------------
1784 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1785  ExistingGraphicLoaded(false), Width(16), Height(16)
1786 {
1787  OriginalGraphic = new Graphics::TBitmap;
1788  OriginalGraphic->PixelFormat = pf8bit;
1789  OriginalGraphic->Width = Width;
1790  OriginalGraphic->Height = Height;
1791  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1792 }
1793 
1794 // ---------------------------------------------------------------------------
1795 
1796 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1797  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1798 {
1799  OriginalGraphic = new Graphics::TBitmap;
1800  OriginalGraphic->PixelFormat = pf8bit;
1801  OriginalGraphic->Width = Width;
1802  OriginalGraphic->Height = Height;
1803  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1804 }
1805 
1806 // ---------------------------------------------------------------------------
1807 
1809 {
1810  delete OriginalGraphic;
1811 }
1812 
1813 // ---------------------------------------------------------------------------
1814 
1815 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1816 {
1817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1818  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1819  VPos = VPosIn;
1820  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1821 
1822  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1823  SourceRect.init(Left, Top, Left + Width, Top + Height);
1824  ScreenSourceSet = true;
1825  Utilities->CallLogPop(422);
1826 }
1827 
1828 // ---------------------------------------------------------------------------
1829 
1831 {
1832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1833  if(!OverlayLoaded)
1834  {
1835  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1836  }
1837  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1838  {
1839  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1840  }
1841  if(!ScreenSourceSet)
1842  {
1843  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1844  }
1845  if(ExistingGraphicLoaded) // can only call one of the load functions
1846  {
1847  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1848  }
1849  if(OverlayPlotted) // don't load from screen if overlay plotted
1850  {
1851  Utilities->CallLogPop(775);
1852  return;
1853  }
1854  TRect DestRect(0, 0, Width, Height);
1855 
1857  OriginalLoaded = true;
1858  ScreenGraphicLoaded = true;
1859  Utilities->CallLogPop(423);
1860 }
1861 
1862 // ---------------------------------------------------------------------------
1863 
1864 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1865 /*
1866  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1867 */
1868 {
1869  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1870  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1871  if(!OverlayLoaded)
1872  {
1873  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1874  }
1875  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1876  {
1877  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1878  }
1879  if(ScreenGraphicLoaded) // can only call one of the load functions
1880  {
1881  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1882  }
1883  Width = WidthIn;
1884  Height = HeightIn;
1885  OriginalGraphic->Width = Width;
1886  OriginalGraphic->Height = Height;
1887  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1888  VPos += VOffset;
1889  TRect DestRect(0, 0, Width, Height);
1890 
1891  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1892  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1893  OriginalLoaded = true;
1894  ExistingGraphicLoaded = true;
1895  Utilities->CallLogPop(424);
1896 }
1897 
1898 // ---------------------------------------------------------------------------
1899 
1900 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1901 {
1902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1903  OverlayGraphic = Overlay;
1904  OverlayLoaded = true;
1905  Utilities->CallLogPop(425);
1906 }
1907 
1908 // ---------------------------------------------------------------------------
1909 
1911 {
1912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1913  if(!OverlayLoaded)
1914  {
1915  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1916  }
1917  if(!OverlayPlotted)
1918  {
1919  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1920  Disp->Update();
1921  OverlayPlotted = true;
1922  }
1923  Utilities->CallLogPop(426);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1931  if(OverlayPlotted)
1932  {
1933  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1934  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1935  {
1936  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1937  }
1938  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1939  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1940  OverlayPlotted = false;
1941  }
1942  Utilities->CallLogPop(427);
1943 }
1944 
1945 // ---------------------------------------------------------------------------
1946 
1948 {
1949  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1950  bool TrackPresent = false;
1951 
1952  if(InactiveTrackVector.size() != 0)
1953  {
1954  Utilities->CallLogPop(1333);
1955  return(false);
1956  }
1957  else if(TrackVector.size() == 0)
1958  {
1959  Utilities->CallLogPop(1334);
1960  return(true);
1961  }
1962  else
1963  {
1964  for(unsigned int x = 0; x < TrackVector.size(); x++)
1965  {
1966  if((TrackElementAt(1042, x).SpeedTag != 0))
1967  {
1968  TrackPresent = true;
1969  }
1970  }
1971  }
1972  Utilities->CallLogPop(1335);
1973  return(!TrackPresent);
1974 }
1975 
1976 // ---------------------------------------------------------------------------
1977 
1978 bool TTrack::NoActiveTrack(int Caller)
1979 {
1980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1981  bool TrackPresent = false;
1982 
1983  if(TrackVector.size() == 0)
1984  {
1985  Utilities->CallLogPop(1582);
1986  return(true);
1987  }
1988  else
1989  {
1990  for(unsigned int x = 0; x < TrackVector.size(); x++)
1991  {
1992  if((TrackElementAt(1043, x).SpeedTag != 0))
1993  {
1994  TrackPresent = true;
1995  }
1996  break;
1997  }
1998  }
1999  Utilities->CallLogPop(1583);
2000  return(!TrackPresent);
2001 }
2002 
2003 // ---------------------------------------------------------------------------
2004 
2005 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2006 {
2007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2008  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2009  TrackEraseSuccessfulFlag = false;
2010 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2011 // since have to match platforms as well as track
2012 // used to set TrackFinished to false if an element erased
2013 
2014  ErasedTrackVectorPosition = -1; // marker for no element erased
2015  AnsiString SName = "", ErrorString;
2017  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2018  TTrackMapIterator TrackMapPtr;
2019  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2020 
2021  if(TrackVector.size() != 0)
2022  {
2023  TrackMapKeyPair.first = HLocInput;
2024  TrackMapKeyPair.second = VLocInput;
2025  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2026  if(TrackMapPtr != TrackMap.end())
2027  {
2028  bool FoundFlag;
2029  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2030  if(FoundFlag) // should find it as it's in the map
2031  {
2032  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2033  {
2034  SName = TrackElementAt(1, VecPos).LocationName;
2035  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2036  if(ErrorString != "")
2037  {
2038  throw Exception(ErrorString + " for EraseTrackElement 1");
2039  }
2040  LocationNameMultiMap.erase(SNIt);
2041  }
2042  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2043  // ensure erase vector element before map element as iterator no longer valid after a map erase
2044  TrackMap.erase(TrackMapPtr);
2045  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2046  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2048  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2049  if(SName != "")
2050  {
2051  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2052  int HPos, VPos;
2053  if(TextHandler->FindText(1, SName, HPos, VPos))
2054  {
2055  if(TextHandler->TextErase(5, HPos, VPos, SName))
2056  {
2057  ;
2058  } // condition not used
2059 
2060  }
2061  }
2062  ErasedTrackVectorPosition = VecPos;
2063  TrackEraseSuccessfulFlag = true;
2064  }
2065  }
2066  }
2067  if(InactiveTrackVector.size() != 0)
2068  {
2069  unsigned int VecPos;
2070  InactiveTrackMapKeyPair.first = HLocInput;
2071  InactiveTrackMapKeyPair.second = VLocInput;
2072  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2073  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2074  {
2075  SName = "";
2076  VecPos = InactiveTrack2MultiMapIterator->second;
2077  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2078  {
2079  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2080  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2081  if(ErrorString != "")
2082  {
2083  throw Exception(ErrorString + " for EraseTrackElement 2A");
2084  }
2085  LocationNameMultiMap.erase(SNIt);
2086  }
2087  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2088  // ensure erase vector element before map element as iterator no longer valid after a map erase
2089  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2090  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2091  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2093  TrackEraseSuccessfulFlag = true;
2094  if(SName != "")
2095  {
2096  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2097  int HPos, VPos;
2098  if(TextHandler->FindText(2, SName, HPos, VPos))
2099  {
2100  if(TextHandler->TextErase(6, HPos, VPos, SName))
2101  {
2102  ;
2103  } // condition not used
2104 
2105  }
2106  }
2107  }
2108  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2109  {
2110  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2111  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2112  {
2113  SName = "";
2114  VecPos = InactiveTrack2MultiMapIterator->second;
2115  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2116  {
2117  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2118  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2119  if(ErrorString != "")
2120  {
2121  throw Exception(ErrorString + " for EraseTrackElement 2B");
2122  }
2123  LocationNameMultiMap.erase(SNIt);
2124  }
2125  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2126  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2127  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2129  if(SName != "")
2130  {
2131  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2132  int HPos, VPos;
2133  if(TextHandler->FindText(3, SName, HPos, VPos))
2134  {
2135  if(TextHandler->TextErase(7, HPos, VPos, SName))
2136  {
2137  ;
2138  } // condition not used
2139 
2140  }
2141  }
2142  }
2143  }
2144  }
2145  if(TrackEraseSuccessfulFlag)
2146  {
2147  CalcHLocMinEtc(2);
2148  SetTrackFinished(false);
2149  }
2150  if(InternalChecks)
2151  {
2152  CheckMapAndTrack(1); // test
2153  CheckMapAndInactiveTrack(1); // test
2154  CheckLocationNameMultiMap(6); // test
2155  }
2156  Utilities->CallLogPop(428);
2157 }
2158 
2159 // ---------------------------------------------------------------------------
2160 
2161 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks, bool PerformNameSearch)
2162 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2163 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2164 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2165 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2166 {
2167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2168  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2169  bool PlatAllowedFlag = false;
2170 
2171  TrackLinkingRequiredFlag = false;
2172 /*
2173  Not erase, that covered separately.
2174  First check if Current SpeedButton assigned, then check if a platform and only
2175  permit if an appropriate trackpiece already there & not a same platform there.
2176  - can't enter a platform without track first.
2177  Then for non-platforms, check if a track piece already present at location &
2178  reject if so.
2179 */
2180 
2181  TLocationNameMultiMapEntry LocationNameEntry;
2182 
2183  LocationNameEntry.first = "";
2184  if(CurrentTag == 0)
2185  {
2186  Utilities->CallLogPop(429);
2187  return; // not assigned yet
2188  }
2189  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2190 
2191  TempTrackElement.HLoc = HLocInput;
2192  TempTrackElement.VLoc = VLocInput;
2193  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2194 // new at version 0.6 - set signal aspect depending on build mode
2195 
2196  if(TempTrackElement.TrackType == SignalPost)
2197  {
2198  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2199  // pasting a SignalPost can only have values 1 to 4
2200  {
2202  {
2203  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2204  }
2206  {
2207  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2208  }
2210  {
2211  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2212  }
2213  else
2214  {
2215  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2216  }
2217  }
2218  else if(Aspect == 1)
2219  {
2220  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2221  }
2222  else if(Aspect == 2)
2223  {
2224  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2225  }
2226  else if(Aspect == 3)
2227  {
2228  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2229  }
2230  else
2231  {
2232  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2233  }
2234  }
2235  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2236  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2237  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2238  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2239 
2240  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2241  {
2243  {
2244  NonStationOrLevelCrossingPresent = true;
2245  }
2246  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2247  {
2248  NonStationOrLevelCrossingPresent = true;
2249  }
2250  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2251  {
2252  PlatformPresent = true;
2253  }
2254  // no need to check IMPair.second since if that exists it is because .first is a platform
2255  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2256  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2257  }
2258 // check platforms
2259  if(TempTrackElement.TrackType == Platform)
2260  {
2261  if(FoundFlag) // active track element already there
2262  {
2263  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2264  {
2265  ;
2266  }
2267  // same platform type already there so above keeps PlatAllowedFlag false
2268  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2269  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2270  {
2271  PlatAllowedFlag = true;
2272  }
2273  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2274  {
2275  PlatAllowedFlag = true;
2276  }
2277  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2278  {
2279  PlatAllowedFlag = true;
2280  }
2281  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2282  {
2283  PlatAllowedFlag = true;
2284  }
2285  if(PlatAllowedFlag)
2286  {
2287  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2288  TrackPush(1, TempTrackElement);
2289  if(PerformNameSearch)
2290  {
2291  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2292  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2293  // Must be called AFTER TrackPush
2294  // No need to plot the element - Clearand ... called after this function called
2295  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2296  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2297  }
2298 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2299 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2300 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2301  if(InternalChecks)
2302  {
2303  CheckMapAndInactiveTrack(5); // test
2304  CheckLocationNameMultiMap(4); // test
2305  }
2306  Utilities->CallLogPop(430);
2307  return;
2308  }
2309  } // if(FoundFlag)
2310 
2311  Utilities->CallLogPop(431);
2312  return;
2313  } // if platform
2314 
2315 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2316  if(TempTrackElement.TrackType == NamedNonStationLocation)
2317  {
2318  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2319  (!FoundFlag && !InactiveFoundFlag))
2320  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2321  {
2322  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2323  TrackPush(2, TempTrackElement);
2324  if(PerformNameSearch)
2325  {
2326  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2327  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2328  }
2329  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2330  {
2331 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2332 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2333 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2334  }
2335  if(InternalChecks)
2336  {
2337  CheckMapAndInactiveTrack(11); // test
2338  CheckLocationNameMultiMap(12); // test
2339  }
2340  Utilities->CallLogPop(432);
2341  return;
2342  }
2343  else
2344  {
2345  Utilities->CallLogPop(433);
2346  return;
2347  }
2348  }
2349 // check if a level crossing - OK if placed on a plain straight track
2350  if(TempTrackElement.TrackType == LevelCrossing)
2351  {
2352  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2353  {
2354  TrackPush(11, TempTrackElement);
2355  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2356 // no need for reference to LC element as can't be open
2357  TrackLinkingRequiredFlag = true;
2358  Utilities->CallLogPop(1907);
2359  return;
2360  }
2361  else
2362  {
2363  Utilities->CallLogPop(1906);
2364  return; // was a level crossing but can't place it for some reason
2365  }
2366  }
2367 
2368 // check if another element already there
2369  else if(FoundFlag || InactiveFoundFlag)
2370  {
2371  Utilities->CallLogPop(434);
2372  return; // something already there (active or inactive track)
2373  }
2374 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2375 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2376 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2377 // do this after pushed into vector so that can use EnterLocationName
2378 
2379  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2380  {
2381  TrackPush(3, TempTrackElement);
2382  if(PerformNameSearch)
2383  {
2384  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2385  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2386  }
2387  }
2388  else if(TempTrackElement.TrackType == Points)
2389  {
2390  TrackPush(4, TempTrackElement);
2391  bool BothPointFillets = true;
2392  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2393  }
2394  else if(TempTrackElement.TrackType == SignalPost)
2395  {
2396  TrackPush(10, TempTrackElement);
2397  PlotSignal(12, TempTrackElement, Display);
2398  }
2399  else
2400  {
2401  TrackPush(5, TempTrackElement);
2402  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2403  }
2404  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2405  {
2406  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2407  }
2408  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2409  {
2410  CheckMapAndTrack(2); // test
2411  CheckMapAndInactiveTrack(2); // test
2412  CheckLocationNameMultiMap(5); // test
2413  }
2414  Utilities->CallLogPop(2062);
2415 }
2416 
2417 // ---------------------------------------------------------------------------
2418 
2419 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2420  bool InternalChecks)
2421 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2422 {
2423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2424  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2425  bool PlatAllowedFlag = false;
2426 
2427  TrackLinkingRequiredFlag = false;
2428  TLocationNameMultiMapEntry LocationNameEntry;
2429 
2430  LocationNameEntry.first = "";
2431  if(TempTrackElement.SpeedTag == 0)
2432  {
2433  Utilities->CallLogPop(2063);
2434  return; // not assigned yet
2435  }
2436  TempTrackElement.HLoc = HLocInput;
2437  TempTrackElement.VLoc = VLocInput;
2438  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2439  for(int x = 0; x < 4; x++) // unset any gaps,
2440  {
2441  if(TempTrackElement.Config[x] == Gap)
2442  {
2443  TempTrackElement.ConnLinkPos[x] = -1;
2444  }
2445  TempTrackElement.Conn[x] = -1;
2446  }
2447  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2448 // new at version 0.6 - set signal aspect depending on build mode
2449  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2450 
2451  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2452  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2453  // for the active track element because these aren't set
2454  // if don't do this then get a mismatch error during map checks later
2455 
2456  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2457 
2458  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2459  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2460 
2461  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2462  {
2463  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2464  {
2465  NonStationOrLevelCrossingPresent = true;
2466  }
2467  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2468  {
2469  NonStationOrLevelCrossingPresent = true;
2470  }
2471  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2472  {
2473  PlatformPresent = true;
2474  }
2475  // no need to check IMPair.second since if that exists it is because .first is a platform
2476  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2477  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2478  }
2479 // check platforms
2480  if(TempTrackElement.TrackType == Platform)
2481  {
2482  if(FoundFlag) // active track element already there
2483  {
2484  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2485  {
2486  ;
2487  }
2488  // same platform type already there so above keeps PlatAllowedFlag false
2489  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2490  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2491  {
2492  PlatAllowedFlag = true;
2493  }
2494  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2495  {
2496  PlatAllowedFlag = true;
2497  }
2498  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2499  {
2500  PlatAllowedFlag = true;
2501  }
2502  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2503  {
2504  PlatAllowedFlag = true;
2505  }
2506  if(PlatAllowedFlag)
2507  {
2508  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2509  TrackPush(12, TempTrackElement);
2510 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2511  {
2512  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2513  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2514  }
2515  // Must be called AFTER TrackPush
2516 // No need to plot the element - Clearand ... called after this function called
2517  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2518  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2519 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2520 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2521 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2522  if(InternalChecks)
2523  {
2524  CheckMapAndInactiveTrack(12); // test
2525  CheckLocationNameMultiMap(20); // test
2526  }
2527  Utilities->CallLogPop(2064);
2528  return;
2529  }
2530  } // if(FoundFlag)
2531 
2532  Utilities->CallLogPop(2065);
2533  return;
2534  } // if platform
2535 
2536 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2537  if(TempTrackElement.TrackType == NamedNonStationLocation)
2538  {
2539  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2540  (!FoundFlag && !InactiveFoundFlag))
2541  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2542  {
2543  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2544  TrackPush(13, TempTrackElement);
2545 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2546  {
2547  {
2548  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2549  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2550  }
2551  }
2552  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2553  {
2554 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2555 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2556 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2557  }
2558  if(InternalChecks)
2559  {
2560  CheckMapAndInactiveTrack(13); // test
2561  CheckLocationNameMultiMap(21); // test
2562  }
2563  Utilities->CallLogPop(2066);
2564  return;
2565  }
2566  else
2567  {
2568  Utilities->CallLogPop(2067);
2569  return;
2570  }
2571  }
2572 // check if a level crossing - OK if placed on a plain straight track
2573  if(TempTrackElement.TrackType == LevelCrossing)
2574  {
2575  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2576  {
2577  TrackPush(14, TempTrackElement);
2578  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2579 // no need for reference to LC element as can't be open
2580  TrackLinkingRequiredFlag = true;
2581  Utilities->CallLogPop(2068);
2582  return;
2583  }
2584  else
2585  {
2586  Utilities->CallLogPop(2069);
2587  return; // was a level crossing but can't place it for some reason
2588  }
2589  }
2590 
2591 // check if another element already there
2592  else if(FoundFlag || InactiveFoundFlag)
2593  {
2594  Utilities->CallLogPop(2070);
2595  return; // something already there (active or inactive track)
2596  }
2597 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2598 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2599 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2600 // do this after pushed into vector so that can use EnterLocationName
2601 
2602  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2603  {
2604  TrackPush(15, TempTrackElement);
2605  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2606  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2607  }
2608  else if(TempTrackElement.TrackType == Points)
2609  {
2610  TrackPush(16, TempTrackElement);
2611  bool BothPointFillets = true;
2612  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2613  }
2614  else if(TempTrackElement.TrackType == SignalPost)
2615  {
2616  TrackPush(17, TempTrackElement);
2617  PlotSignal(14, TempTrackElement, Display);
2618  }
2619  else
2620  {
2621  TrackPush(18, TempTrackElement);
2622  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2623  }
2624  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2625  {
2626  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2627  }
2628  if(InternalChecks)
2629  {
2630  CheckMapAndTrack(12); // test
2631  CheckMapAndInactiveTrack(14); // test
2632  CheckLocationNameMultiMap(22); // test
2633  }
2634  Utilities->CallLogPop(2071);
2635 }
2636 
2637 // ---------------------------------------------------------------------------
2638 
2639 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2640 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2641 // return bool = true for success
2642 // LocError = true for location error & HLoc & VLoc to be inverted
2643 {
2644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2645  LocError = false;
2646  SetTrackFinished(false);
2647  if(TrackVector.size() == 0)
2648  {
2649  Utilities->CallLogPop(437);
2650  return(false);
2651  }
2652  if(GapsUnset(7))
2653  {
2654  if(GiveMessages)
2655  {
2656  ShowMessage("Gaps must be set before track can be validated");
2657  }
2658  Utilities->CallLogPop(1135);
2659  return(false);
2660  }
2661 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2662 // returns true for any unset gaps
2664  {
2665  // can keep this exception as protected by the GapsUnset call above
2666  throw Exception("Error, gaps unset when TryToConnectTrack called");
2667  }
2669  CheckGapMap(1); // test
2670 // Gap connections now securely defined
2671 
2672  CheckMapAndTrack(8); // test
2673 
2674 // Perform a pre-check prior to TrackMap being compiled
2675  if(GiveMessages)
2676  {
2677  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2678  {
2679  Utilities->CallLogPop(439);
2680  return(false);
2681  }
2682  }
2683  else
2684  {
2685  if(!LinkTrackNoMessages(1, false))
2686  {
2687  Utilities->CallLogPop(1131);
2688  return(false);
2689  }
2690  }
2691 // here if pre-check successful
2692  if(!RepositionAndMapTrack(0))
2693  {
2694  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2695  Utilities->CallLogPop(1138);
2696  return(false);
2697  }
2698 // now perform the final assembly - FinalCall = true
2699  if(GiveMessages)
2700  {
2701  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2702  {
2703  Utilities->CallLogPop(1116);
2704  return(false);
2705  }
2706  }
2707  else
2708  {
2709  if(!LinkTrackNoMessages(2, true))
2710  {
2711  Utilities->CallLogPop(1132);
2712  return(false);
2713  }
2714  }
2715 // success
2716 
2717  PopulateLCVector(0);
2718  CheckGapMap(2); // test
2719  CheckMapAndTrack(3); // test
2720  CheckMapAndInactiveTrack(3); // test
2721  CheckLocationNameMultiMap(9); // test
2722  SetTrackFinished(true);
2723 
2724 // Build ContinuationNameMap
2725  std::pair<AnsiString, char>TempMapPair;
2726 
2727  ContinuationNameMap.clear();
2728  for(int x = 0; x < Track->TrackVectorSize(); x++)
2729  {
2730  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2731  {
2732  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2733  TempMapPair.second = 'x'; // unused
2734  ContinuationNameMap.insert(TempMapPair);
2735  }
2736  }
2737 
2738 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2739 //(don't report blue areas without track as these unlikely to be mistakes)
2740 
2741  if(TrackFinished)
2742  {
2743  AnsiString Name = "";
2744  typedef std::list<AnsiString> TNoPlatsList;
2745  TNoPlatsList::iterator NPLIt;
2746  TNoPlatsList NoPlatsList;
2747  typedef std::list<AnsiString> TLocNameList;
2748  TLocNameList LocNameList; //single entry for each name
2751  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2752  {
2753  LocNameList.push_back(LNMMIt->first);
2754  }
2755  LocNameList.sort();
2756  LocNameList.unique();
2757  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2758  {
2759  Name = *LNLIt;
2760  MMRange = LocationNameMultiMap.equal_range(Name);
2761  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2762  {
2763  continue;
2764  }
2765  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2766  {
2767  if((LNMMIt->second) < 0) //active track element
2768  {
2769  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2770  {
2771  break;
2772  }
2773  }
2774  else //inactive
2775  {
2776  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2777  {
2778  break;
2779  }
2780  }
2781  TempIt = MMRange.second;
2782  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2783  {
2784  NoPlatsList.push_back(Name);
2785  }
2786  }
2787  }
2788  if(!NoPlatsList.empty())
2789  {
2790  AnsiString NoPlatsAnsiList = "";
2791  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2792  {
2793  NoPlatsAnsiList += *NPLIt + '\n';
2794  }
2796  {
2797  if(NoPlatsList.size() > 1)
2798  {
2799  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2800  }
2801  else
2802  {
2803  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2804  }
2805  Utilities->NoPlatsMessageSent = true;
2806  }
2807  }
2808  }
2809  Utilities->CallLogPop(440);
2810  return(true);
2811 }
2812 
2813 // ---------------------------------------------------------------------------
2814 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2815 // unused - too time-consuming - double brute force search
2816 {
2817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2818  int NewHLoc, NewVLoc;
2819  bool ConnectionFoundFlag, LinkFoundFlag;
2820 
2821  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2822  {
2823  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2824  {
2825  if(TrackElementAt(1061, x).Link[y] <= 0)
2826  {
2827  continue; // no link
2828  }
2829  if(TrackElementAt(1062, x).Config[y] == End)
2830  {
2831  continue; // buffer or continuation
2832  }
2833  if(TrackElementAt(1063, x).Config[y] == Gap)
2834  {
2835  continue; // gap jump
2836  }
2837  // get required H & V for track element joining link 'y'
2838  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2839  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2840  // find track element if present
2841  ConnectionFoundFlag = false;
2842  for(unsigned int z = 0; z < TrackVector.size(); z++)
2843  {
2844 // if(TrackElementAt(5, z).TrackType == Platform)
2845 // continue; //skip platforms
2846  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2847  {
2848  ConnectionFoundFlag = true;
2849  // find connecting link in the newly found track element if there is one
2850  LinkFoundFlag = false;
2851  for(unsigned int a = 0; a < 4; a++)
2852  {
2853  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2854  {
2855  LinkFoundFlag = true;
2856  }
2857  }
2858  // if there isn't a corresponding link set the invert values for the offending element
2859  if(!LinkFoundFlag)
2860  {
2861  HLoc = TrackElementAt(1072, x).HLoc;
2862  VLoc = TrackElementAt(1073, x).VLoc;
2863  Utilities->CallLogPop(441);
2864  return(true);
2865  }
2866  break; // success, so break out of 'z' loop
2867  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2868 
2869  } // for z...
2870  // if there isn't a connection set the invert values for the offending element
2871  if(!ConnectionFoundFlag)
2872  {
2873  HLoc = TrackElementAt(1074, x).HLoc;
2874  VLoc = TrackElementAt(1075, x).VLoc;
2875  Utilities->CallLogPop(442);
2876  return(true);
2877  }
2878  } // for y....
2879  } // for x...
2880  Utilities->CallLogPop(443);
2881  return(false); // all OK
2882 }
2883 
2884 // ---------------------------------------------------------------------------
2885 
2886 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2887 {
2888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2889  TrackElement.LogTrack(0));
2890  bool FoundFlag;
2891 
2892  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2893  if(FoundFlag)
2894  {
2895  TrackElement = TrackElementAt(1076, Position);
2896  }
2897  Utilities->CallLogPop(444);
2898  return(FoundFlag);
2899 }
2900 
2901 // ---------------------------------------------------------------------------
2902 
2904 {
2905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2906  if(NextTrackElementPtr >= TrackVector.end())
2907  {
2908  Utilities->CallLogPop(1336);
2909  return(false);
2910  }
2911  Next = *NextTrackElementPtr;
2913  Utilities->CallLogPop(1337);
2914  return(true);
2915 }
2916 
2917 // ---------------------------------------------------------------------------
2918 
2920 {
2921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2923  {
2924  Utilities->CallLogPop(1338);
2925  return(false);
2926  }
2927  Next = *NextTrackElementPtr;
2929  Utilities->CallLogPop(1339);
2930  return(true);
2931 }
2932 
2933 // ---------------------------------------------------------------------------
2934 
2935 int TTrack::NumberOfGaps(int Caller)
2936 
2937 {
2938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2939  int Count = 0;
2940 
2941  if(TrackVector.size() == 0)
2942  {
2943  Utilities->CallLogPop(1340);
2944  return(0);
2945  }
2946  for(unsigned int x = 0; x < TrackVector.size(); x++)
2947  {
2948  if(TrackElementAt(1077, x).TrackType == GapJump)
2949  {
2950  Count++;
2951  }
2952  }
2953  Utilities->CallLogPop(1341);
2954  return(Count);
2955 }
2956 
2957 // ---------------------------------------------------------------------------
2959 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2960 // returns true for any unset gaps
2961 {
2962  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2963  bool UnsetGaps = false;
2964 
2965  if(TrackVector.size() == 0)
2966  {
2967  Utilities->CallLogPop(445);
2968  return(false);
2969  }
2970  for(unsigned int x = 0; x < TrackVector.size(); x++)
2971  {
2972  if(TrackElementAt(1078, x).TrackType != GapJump)
2973  {
2974  for(unsigned int y = 0; y < 4; y++)
2975  {
2976  TrackElementAt(1079, x).Conn[y] = -1;
2977  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2978  }
2979  }
2980  else // GapJump
2981  {
2982 // int tempint = TrackElementAt(, x).Conn[0);
2983 
2984  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2985  {
2986  for(unsigned int y = 0; y < 4; y++)
2987  {
2988  TrackElementAt(1082, x).Conn[y] = -1;
2989  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2990  }
2991  UnsetGaps = true;
2992  continue; // to next 'x'
2993  }
2994  else // set, but may not have matching element, or that element may not be set
2995  {
2996  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2997  {
2998  TrackElementAt(1084, x).Conn[y] = -1;
2999  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
3000  }
3001 
3002  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3003  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3004  {
3005  for(unsigned int y = 0; y < 4; y++)
3006  {
3007  TrackElementAt(1087, x).Conn[y] = -1;
3008  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3009  }
3010  UnsetGaps = true;
3011  continue; // to next 'x'
3012  }
3013 // here if gap connection is itself a GapJump
3014  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3015  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3016  // if not clear Conns & CLks & reset Lk[0]
3017  {
3018  for(unsigned int y = 0; y < 4; y++)
3019  {
3020  TrackElementAt(1090, x).Conn[y] = -1;
3021  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3022  }
3023  UnsetGaps = true;
3024  continue; // to next 'x'
3025  }
3026 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3027 // hence no more action needed on these Conns & CLks
3028  }
3029  } // else //gap jump
3030 
3031  } // for x...
3032  Utilities->CallLogPop(446);
3033  return(UnsetGaps);
3034 }
3035 
3036 // ---------------------------------------------------------------------------
3037 
3038 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3039 {
3040 // VecFile already open and its pointer at right place on calling
3041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3042  int TempInt;
3043 
3044  TrackClear(1);
3045 // load track elements
3046  int NumberOfActiveElements = 0;
3047 
3048  GraphicsFollow = false;
3049  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3050  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3051 
3052  if(MarkerString[MarkerString.Length()] == '1')
3053  {
3054  GraphicsFollow = true;
3055  }
3056  for(int x = 0; x < NumberOfActiveElements; x++)
3057  {
3058  VecFile >> TempInt; // TrackVectorNumber, not used
3059  VecFile >> TempInt; // SpeedTag
3060  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3061  VecFile >> TempInt;
3062  TrackElement.HLoc = TempInt;
3063  VecFile >> TempInt;
3064  TrackElement.VLoc = TempInt;
3065  if(TrackElement.TrackType == GapJump)
3066  {
3067  VecFile >> TempInt;
3068  TrackElement.ConnLinkPos[0] = TempInt;
3069  VecFile >> TempInt;
3070  TrackElement.Conn[0] = TempInt;
3071  }
3072  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3073  {
3074  VecFile >> TempInt;
3075  TrackElement.Attribute = TempInt;
3076  }
3077  if(TrackElement.TrackType == SignalPost)
3078  {
3079  VecFile >> TempInt;
3080  if(TempInt == 0)
3081  {
3082  TrackElement.CallingOnSet = false;
3083  }
3084  else
3085  {
3086  TrackElement.CallingOnSet = true;
3087  }
3088  }
3089  VecFile >> TempInt;
3090  TrackElement.Length01 = TempInt;
3091  VecFile >> TempInt;
3092  TrackElement.Length23 = TempInt;
3093  VecFile >> TempInt;
3094  if((TempInt != -1) && (TempInt < 10))
3095  {
3096  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3097  }
3098  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3099  {
3100  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3101  }
3102  TrackElement.SpeedLimit01 = TempInt;
3103  VecFile >> TempInt;
3104  if((TempInt != -1) && (TempInt < 10))
3105  {
3106  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3107  }
3108  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3109  {
3110  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3111  }
3112  TrackElement.SpeedLimit23 = TempInt;
3113 
3114  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3115  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3116  SetElementID(0, TrackElement);
3117  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3118 // new for v0.6
3119  if(TrackElement.TrackType == SignalPost)
3120  {
3121  if(Marker[1] == '3')
3122  {
3123  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3124  }
3125  else if(Marker[1] == '2')
3126  {
3127  TrackElement.SigAspect = TTrackElement::TwoAspect;
3128  }
3129  else if(Marker[1] == 'G')
3130  {
3131  TrackElement.SigAspect = TTrackElement::GroundSignal;
3132  }
3133  else
3134  {
3135  TrackElement.SigAspect = TTrackElement::FourAspect;
3136  }
3137  }
3138  if(TrackElement.SpeedTag != 0)
3139  {
3140  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3141  }
3142  }
3143  int NumberOfInactiveElements = 0;
3144 
3145  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3146  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3147  for(int x = 0; x < NumberOfInactiveElements; x++)
3148  {
3149  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3150  VecFile >> TempInt; // SpeedTag
3151  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3152  VecFile >> TempInt;
3153  TrackElement.HLoc = TempInt;
3154  VecFile >> TempInt;
3155  TrackElement.VLoc = TempInt;
3156  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3157  SetElementID(3, TrackElement);
3158  TrackPush(9, TrackElement);
3159  Utilities->LoadFileString(VecFile); // marker
3160  }
3161  bool LocError = false; // needed for TryToConnectTrack but not used
3162  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3163 
3164  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3165  {
3166  SetTrackFinished(true);
3167  }
3168  else
3169  {
3170  SetTrackFinished(false);
3171  }
3172 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3173 // CheckMapAndInactiveTrack(8);
3174 // CheckLocationNameMultiMap(10);
3175  Utilities->CallLogPop(448);
3176 }
3177 
3178 // ---------------------------------------------------------------------------
3179 
3180 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3181 {
3182 // VecFile already open and its pointer at right place on calling
3183  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3184 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3185 // & load into UserGraphicItem then store in UserGraphicVector
3186  UserGraphicVector.clear();
3187  TUserGraphicItem UGI;
3188  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3189 
3190  for(int x = 0; x < NumberOfGraphics; x++)
3191  {
3192  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3193  UGI.HPos = Utilities->LoadFileInt(VecFile);
3194  UGI.VPos = Utilities->LoadFileInt(VecFile);
3195  UGI.Width = 0; // provisional value
3196  UGI.Height = 0; // provisional value
3197  UGI.UserGraphic = NULL; // provisional value
3198  UserGraphicVector.push_back(UGI);
3199  }
3200 // now load the map & set Width, Height & TPicture*
3201  bool FileError = false;
3202 
3203  for(int x = 0; x < NumberOfGraphics; x++)
3204  {
3205  if(FileError)
3206  {
3207  break; // otherwise keeps going round the loop
3208  }
3209  UGI = UserGraphicVectorAt(0, x);
3210  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3211  {
3212  try
3213  {
3214 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3215  UGME.first = UGI.FileName;
3216  UGME.second = new TPicture;
3217  UGME.second->LoadFromFile(UGME.first); // errors caught below
3218  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3219  {
3220  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3221  }
3222  UGI.UserGraphic = UGME.second;
3223  UGI.Width = UGI.UserGraphic->Width;
3224  UGI.Height = UGI.UserGraphic->Height;
3225  UserGraphicVectorAt(1, x) = UGI;
3226  }
3227  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3228  {
3229  //message already sent in CheckUserGraphics
3230  FileError = true;
3231  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3232  if(!UserGraphicMap.empty())
3233  {
3234  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3235  {
3236  delete UGMIt->second;
3237  }
3238  UserGraphicMap.clear();
3239  }
3240  }
3241  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3242  {
3243  //message already sent in CheckUserGraphics
3244  FileError = true;
3245  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3246  if(!UserGraphicMap.empty())
3247  {
3248  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3249  {
3250  delete UGMIt->second;
3251  }
3252  UserGraphicMap.clear();
3253  }
3254  }
3255  }
3256  else
3257  {
3258  bool FoundInMap = false;
3259  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3260  {
3261  if(UGI.FileName == UGMIt->first) // already exists in map
3262  {
3263  UGI.UserGraphic = UGMIt->second;
3264  UGI.Width = UGI.UserGraphic->Width;
3265  UGI.Height = UGI.UserGraphic->Height;
3266  UserGraphicVectorAt(2, x) = UGI;
3267  FoundInMap = true;
3268  break;
3269  }
3270  }
3271  if(!FoundInMap)
3272  {
3273  try
3274  {
3276  UGME.first = UGI.FileName;
3277  UGME.second = new TPicture;
3278  UGME.second->LoadFromFile(UGME.first); // errors caught below
3279  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3280  {
3281  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3282  }
3283  UGI.UserGraphic = UGME.second;
3284  UGI.Width = UGI.UserGraphic->Width;
3285  UGI.Height = UGI.UserGraphic->Height;
3286  UserGraphicVectorAt(3, x) = UGI;
3287  }
3288  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3289  {
3290  //message already sent in CheckUserGraphics
3291  FileError = true;
3292  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3293  if(!UserGraphicMap.empty())
3294  {
3295  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3296  {
3297  delete UGMIt->second;
3298  }
3299  UserGraphicMap.clear();
3300  }
3301  }
3302  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3303  {
3304  //message already sent in CheckUserGraphics
3305  FileError = true;
3306  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3307  if(!UserGraphicMap.empty())
3308  {
3309  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3310  {
3311  delete UGMIt->second;
3312  }
3313  UserGraphicMap.clear();
3314  }
3315  }
3316  }
3317  }
3318  }
3319  Utilities->CallLogPop(2167);
3320 }
3321 
3322 // ---------------------------------------------------------------------------
3323 
3324 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3325 {
3326 // VecFile already open and its pointer at right place on calling
3327 // if GraphicsFollow true, then save Marker as **Active elements**1
3328 // save trackfinished flag
3329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3330  TTrackElement TrackElement, InactiveTrackElement;
3331 
3332 // save track elements
3333  Utilities->SaveFileInt(VecFile, TrackVector.size());
3334  if(GraphicsFollow)
3335  {
3336  VecFile << "**Active elements**1" << '\0' << '\n';
3337  }
3338  else
3339  {
3340  VecFile << "**Active elements**" << '\0' << '\n';
3341  }
3342  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3343  {
3344  TrackElement = TrackElementAt(1092, x);
3345  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3346  VecFile << TrackElement.SpeedTag << '\n';
3347  VecFile << TrackElement.HLoc << '\n';
3348  VecFile << TrackElement.VLoc << '\n';
3349  if(TrackElement.TrackType == GapJump)
3350  {
3351  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3352  VecFile << TrackElement.Conn[0] << '\n';
3353  }
3354  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3355  {
3356  VecFile << TrackElement.Attribute << '\n';
3357  }
3358  if(TrackElement.TrackType == SignalPost)
3359  {
3360  if(TrackElement.CallingOnSet)
3361  {
3362  VecFile << int(1) << '\n';
3363  }
3364  else
3365  {
3366  VecFile << int(0) << '\n';
3367  }
3368  }
3369  VecFile << TrackElement.Length01 << '\n';
3370  VecFile << TrackElement.Length23 << '\n';
3371  VecFile << TrackElement.SpeedLimit01 << '\n';
3372  VecFile << TrackElement.SpeedLimit23 << '\n';
3373  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3375 // new for v0.6
3376  if(TrackElement.TrackType == SignalPost)
3377  {
3378  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3379  {
3380  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3381  }
3382  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3383  {
3384  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3385  }
3386  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3387  {
3388  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3389  }
3390  else // 4 aspect
3391  {
3392  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3393  }
3394  }
3395  else
3396  {
3397  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3398  }
3399  }
3400 
3401  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3402  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3403  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3404  {
3405  InactiveTrackElement = InactiveTrackElementAt(136, x);
3406  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3407  VecFile << InactiveTrackElement.SpeedTag << '\n';
3408  VecFile << InactiveTrackElement.HLoc << '\n';
3409  VecFile << InactiveTrackElement.VLoc << '\n';
3410  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3411  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3412  }
3413  Utilities->CallLogPop(449);
3414 }
3415 
3416 // ---------------------------------------------------------------------------
3417 
3418 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3419 {
3420 // VecFile already open and its pointer at right place on calling
3421 // check trackfinished flag
3422 // inactive elements follow immediately after active elements, no need to check for a marker between them
3423  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3424  int TempInt;
3425 
3426  GraphicsFollow = false;
3427  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3428  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3429  {
3430  Utilities->CallLogPop(1513);
3431  return(false);
3432  }
3433 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3434  AnsiString MarkerString;
3435 
3436  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3437  {
3438  Utilities->CallLogPop(1758);
3439  return(false);
3440  }
3441  if(MarkerString[MarkerString.Length()] == '1')
3442  {
3443  GraphicsFollow = true;
3444  }
3445  for(int x = 0; x < NumberOfActiveElements; x++)
3446  {
3447  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3448  {
3449  Utilities->CallLogPop(1759);
3450  return(false);
3451  }
3452  VecFile >> TempInt;
3453  int SpeedTag = TempInt;
3454  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3455  {
3456  Utilities->CallLogPop(1514);
3457  return(false);
3458  }
3459  VecFile >> TempInt;
3460  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3461  {
3462  Utilities->CallLogPop(1495);
3463  return(false);
3464  }
3465  VecFile >> TempInt;
3466  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3467  {
3468  Utilities->CallLogPop(1497);
3469  return(false);
3470  }
3471  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3472  {
3473  VecFile >> TempInt;
3474  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3475  {
3476  Utilities->CallLogPop(1499);
3477  return(false);
3478  }
3479  VecFile >> TempInt;
3480  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3481  {
3482  Utilities->CallLogPop(1500);
3483  return(false);
3484  }
3485  }
3486  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3487  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3488  {
3489  VecFile >> TempInt;
3490  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3491  {
3492  Utilities->CallLogPop(1502);
3493  return(false);
3494  }
3495  }
3496  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3497  {
3498  VecFile >> TempInt;
3499  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3500  {
3501  Utilities->CallLogPop(1155);
3502  return(false);
3503  }
3504  }
3505  VecFile >> TempInt;
3506  if((TempInt < -1) || (TempInt > 999999)) // Length01
3507  {
3508  Utilities->CallLogPop(1503);
3509  return(false);
3510  }
3511  VecFile >> TempInt;
3512  if((TempInt < -1) || (TempInt > 999999)) // Length23
3513  {
3514  Utilities->CallLogPop(1504);
3515  return(false);
3516  }
3517  VecFile >> TempInt;
3518  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3519  {
3520  Utilities->CallLogPop(1505);
3521  return(false);
3522  }
3523  VecFile >> TempInt;
3524  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3525  {
3526  Utilities->CallLogPop(1506);
3527  return(false);
3528  }
3529  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3530  {
3531  Utilities->CallLogPop(1142);
3532  return(false); // LocationName
3533  }
3534  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3535  {
3536  Utilities->CallLogPop(1143);
3537  return(false); // ActiveTrackElementName
3538  }
3539  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3540  {
3541  Utilities->CallLogPop(1787);
3542  return(false); // marker
3543  }
3544  }
3545  int NumberOfInactiveElements = 0;
3546 
3547  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3548  if(NumberOfInactiveElements < 0) // No of active elements
3549  {
3550  Utilities->CallLogPop(1493);
3551  return(false);
3552  }
3553  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3554  {
3555  Utilities->CallLogPop(1764);
3556  return(false); // **Inactive elements** marker
3557  }
3558  for(int x = 0; x < NumberOfInactiveElements; x++)
3559  {
3560  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3561  {
3562  Utilities->CallLogPop(1765);
3563  return(false);
3564  }
3565  VecFile >> TempInt;
3566  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3567  {
3568  Utilities->CallLogPop(1494);
3569  return(false);
3570  }
3571  VecFile >> TempInt;
3572  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3573  {
3574  Utilities->CallLogPop(1496);
3575  return(false);
3576  }
3577  VecFile >> TempInt;
3578  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3579  {
3580  Utilities->CallLogPop(1498);
3581  return(false);
3582  }
3583  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3584  {
3585  Utilities->CallLogPop(1144);
3586  return(false); // LocationName
3587  }
3588  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3589  {
3590  Utilities->CallLogPop(1788);
3591  return(false); // marker
3592  }
3593  }
3594  Utilities->CallLogPop(1507);
3595  return(true);
3596 }
3597 
3598 // ---------------------------------------------------------------------------
3599 
3600 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3601 {
3602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3603  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3604 
3605  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3606  {
3607  Utilities->CallLogPop(2168);
3608  return(false);
3609  }
3610  // filename in Graphics folder, then HPos, then VPos
3611  AnsiString FileName = "", TempStr = "";
3612 
3613  for(int x = 0; x < NumberOfGraphics; x++)
3614  {
3615  TPicture *TempPicture = new TPicture;
3616  try
3617  {
3618  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3619  {
3620  Utilities->CallLogPop(2169);
3621  delete TempPicture;
3622  return(false);
3623  }
3624  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3625  delete TempPicture;
3626  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3627  {
3628  Utilities->CallLogPop(2170);
3629  return(false);
3630  }
3631  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3632  {
3633  Utilities->CallLogPop(2171);
3634  return(false);
3635  }
3636  }
3637  catch(const EInvalidGraphic &e) //non error catch
3638  {
3639  //move file pointer to end of graphic section for later checks in session files
3640  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3641  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3642  for(int y = x + 1; y < NumberOfGraphics; y++)
3643  {
3644  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3645  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3646  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3647  }
3648  ShowMessage(FileName +
3649  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3650  Utilities->CallLogPop(2172);
3651  delete TempPicture;
3652  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3653  }
3654  catch(const Exception &e) //non error catch
3655  {
3656  //move file pointer to end of graphic section for later checks in session files
3657  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3658  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3659  for(int y = x + 1; y < NumberOfGraphics; y++)
3660  {
3661  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3662  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3663  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3664  }
3665  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3666  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3667  Utilities->CallLogPop(2173);
3668  delete TempPicture;
3669  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3670  }
3671  }
3672  Utilities->CallLogPop(2174);
3673  return(true);
3674 }
3675 
3676 // ---------------------------------------------------------------------------
3677 
3678 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3679 {
3680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3681  int VecSize = Track->BarriersDownVector.size();
3682 
3683  Utilities->SaveFileInt(OutFile, VecSize);
3684  for(int x = 0; x < VecSize; x++)
3685  {
3687  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3688  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3689  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3690  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3691  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3692  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3693  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3694  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3695  }
3696  Utilities->CallLogPop(1963);
3697 }
3698 
3699 // ---------------------------------------------------------------------------
3700 
3701 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3702 {
3703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3704  int VecSize = Track->ChangingLCVector.size();
3705 
3706  Utilities->SaveFileInt(OutFile, VecSize);
3707  for(int x = 0; x < VecSize; x++)
3708  {
3710  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3711  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3712  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3713  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3714  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3715  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3716  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3717  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3718  }
3719  Utilities->CallLogPop(1980);
3720 }
3721 
3722 // ---------------------------------------------------------------------------
3723 
3724 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3725 {
3726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3727  int VecSize = Utilities->LoadFileInt(VecFile);
3728 
3729  for(int x = 0; x < VecSize; x++)
3730  {
3731  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3732  {
3733  Utilities->CallLogPop(1970);
3734  return(false);
3735  }
3736  if(!Utilities->CheckFileBool(VecFile))
3737  {
3738  Utilities->CallLogPop(1971);
3739  return(false);
3740  }
3741  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3742  {
3743  Utilities->CallLogPop(1972);
3744  return(false);
3745  }
3746  if(!Utilities->CheckFileDouble(VecFile))
3747  {
3748  Utilities->CallLogPop(1973);
3749  return(false);
3750  }
3751  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3752  {
3753  Utilities->CallLogPop(1974);
3754  return(false);
3755  }
3756  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3757  {
3758  Utilities->CallLogPop(1975);
3759  return(false);
3760  }
3761  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3762  {
3763  Utilities->CallLogPop(1976);
3764  return(false);
3765  }
3766  if(!Utilities->CheckFileDouble(VecFile))
3767  {
3768  Utilities->CallLogPop(1977);
3769  return(false);
3770  }
3771  }
3772  Utilities->CallLogPop(1978);
3773  return(true);
3774 }
3775 
3776 // ---------------------------------------------------------------------------
3777 
3778 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3779 {
3780  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3781  int VecSize = Utilities->LoadFileInt(VecFile);
3782 
3783  for(int x = 0; x < VecSize; x++)
3784  {
3785  TActiveLevelCrossing TALC;
3786  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3787  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3788  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3789  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3790  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3791  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3792  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3793  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3794  BarriersDownVector.push_back(TALC);
3795  }
3796  Utilities->CallLogPop(1979);
3797 }
3798 
3799 // ---------------------------------------------------------------------------
3800 
3801 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3802 /*
3803  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3804  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3805  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3806 */
3807 {
3808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3809  TTrackElement Next;
3810 
3811  Track->RebuildUserGraphics(0, HiddenDisplay); //moved here from Clearand... so user graphics overwrites LongServRef names
3813  while(ReturnNextInactiveTrackElement(0, Next))
3814  {
3815  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3816  {
3817  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3818  {
3819  // only plot if on screen, to save time (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3820  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3821  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3822  {
3823  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3824  }
3825  }
3826  }
3827  }
3828 
3829  NextTrackElementPtr = TrackVector.begin();
3830  while(ReturnNextTrackElement(0, Next))
3831  {
3832  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3833  {
3834  // only plot if on screen, to save time (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3835  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3836  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3837  {
3838  if(Next.TrackType == Points)
3839  {
3840  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3842  {
3843  OneLengthOrSpeedHeatMapColour(0, Next, true, Disp); //true for 01 length
3844  OneLengthOrSpeedHeatMapColour(1, Next, false, Disp); //false for 23 length
3845  }
3846  }
3847  else if(Next.TrackType == SignalPost)
3848  {
3849  PlotSignal(9, Next, Disp);
3851  {
3852  OneLengthOrSpeedHeatMapColour(2, Next, true, Disp); //true for 01 length
3853  }
3854  }
3855  else if(Next.TrackType == GapJump)
3856  {
3857  PlotGap(0, Next, Disp);
3859  {
3860  OneLengthOrSpeedHeatMapColour(3, Next, true, Disp); //true for 01 length
3861  }
3862  }
3863  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3864  {
3865  PlotContinuation(0, Next, Disp);
3867  {
3868  OneLengthOrSpeedHeatMapColour(4, Next, true, Disp); //true for 01 length
3869  }
3870  }
3871  else if(Next.TrackType == Crossover || Next.TrackType == Bridge)
3872  {
3873  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3875  {
3876  OneLengthOrSpeedHeatMapColour(5, Next, true, Disp); //true for 01 length
3877  OneLengthOrSpeedHeatMapColour(6, Next, false, Disp); //false for 23 length
3878  }
3879  }
3880  else
3881  {
3882  Next.PlotVariableTrackElement(13, Disp); // for footcrossings, may be striped or not
3884  {
3885  OneLengthOrSpeedHeatMapColour(7, Next, true, Disp); //true for 01 length
3886  }
3887  }
3888  }
3889  }
3890  }
3891 
3892  if(BothPointFilletsAndBasicLCs)
3893  {
3895  while(ReturnNextInactiveTrackElement(4, Next))
3896  {
3897  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3898  {
3899  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3900  {
3901  // only plot if on screen, to save time, & OK as plotting one by one here (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3902  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3903  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3904  {
3905  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3906  {
3907  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3908  }
3909  else
3910  {
3911  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3912  }
3913  }
3914  }
3915  }
3916  }
3917  }
3918 
3919  TextHandler->RebuildFromTextVector(1, Disp); // plot text after all else so visible over stations/track etc. //moved from above at v2.20.3
3920  Disp->Update();
3921  Utilities->CallLogPop(468);
3922 }
3923 
3924 // ---------------------------------------------------------------------------
3925 
3926 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3927 {
3928  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3929  if(UserGraphicVector.empty())
3930  {
3931  Utilities->CallLogPop(2175);
3932  return;
3933  }
3934  TUserGraphicItem UGI;
3935 
3936  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3937  {
3938  UGI = UserGraphicVectorAt(4, x);
3939  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3940  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3941  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3942  {
3943  Disp->PlotAndAddUserGraphic(0, UGI);
3944  }
3945  }
3946  Disp->Update();
3947  Utilities->CallLogPop(2176);
3948 }
3949 
3950 // ---------------------------------------------------------------------------
3951 
3952 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3953 /*
3954  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3955 */
3956 {
3957  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3958 // need to change graphics back to black on white if have a dark background
3959  TColor OldTransparentColour = Utilities->clTransparent;
3960 
3962  {
3963  Utilities->clTransparent = TColor(0xFFFFFF); // white
3966  }
3967  TTrackElement Next;
3968 
3969  Bitmap->Canvas->CopyMode = cmSrcCopy;
3971  Graphics::TBitmap *GraphicOutput;
3972 
3973  while(ReturnNextInactiveTrackElement(2, Next))
3974  {
3975  GraphicOutput = Next.GraphicPtr;
3976  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3977  {
3978  if(Next.LocationName == "") // plot as named or unnamed (striped)
3979  {
3980  // default is not striped
3981  switch(Next.SpeedTag)
3982  {
3983  case 76: // t platform
3984  GraphicOutput = RailGraphics->gl76Striped;
3985  break;
3986 
3987  case 77: // h platform
3988  GraphicOutput = RailGraphics->bm77Striped;
3989  break;
3990 
3991  case 78: // v platform
3992  GraphicOutput = RailGraphics->bm78Striped;
3993  break;
3994 
3995  case 79: // r platform
3996  GraphicOutput = RailGraphics->gl79Striped;
3997  break;
3998 
3999  case 96: // concourse
4000  GraphicOutput = RailGraphics->ConcourseStriped;
4001  break;
4002 
4003  case 129: // v footbridge
4004  GraphicOutput = RailGraphics->gl129Striped;
4005  break;
4006 
4007  case 130: // h footbridge
4008  GraphicOutput = RailGraphics->gl130Striped;
4009  break;
4010 
4011  case 131: // non-station named loc
4012  GraphicOutput = RailGraphics->bmNameStriped;
4013  break;
4014 
4015  case 145: // v underpass
4016  GraphicOutput = RailGraphics->gl145Striped;
4017  break;
4018 
4019  case 146: // h underpass
4020  GraphicOutput = RailGraphics->gl146Striped;
4021  break;
4022 
4023  default:
4024  GraphicOutput = Next.GraphicPtr;
4025  break;
4026  }
4027  }
4028  if(Next.SpeedTag == 144) // level crossing
4029  {
4030  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
4031  {
4032  GraphicOutput = RailGraphics->LCBothVer;
4033  }
4034  else
4035  {
4036  GraphicOutput = RailGraphics->LCBothHor;
4037  }
4038  }
4039  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4040  }
4041  }
4042 
4043  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4044 
4045 
4046  NextTrackElementPtr = TrackVector.begin();
4047  while(ReturnNextTrackElement(2, Next))
4048  {
4049  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4050  {
4051  if(Next.TrackType == Points) // plot both fillets
4052  {
4053  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4054  if(Next.SpeedTag < 28)
4055  {
4056  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4058  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4060  }
4061  else if(Next.SpeedTag < 132)
4062  {
4063  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4064  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4065  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4066  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4067  }
4068  else
4069  {
4070  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4071  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4072  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4073  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4074  }
4075  }
4076  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4077  {
4078  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4079  {
4080  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4081  }
4082  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4083  {
4084  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4085  }
4086  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4087  {
4088  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4089  }
4090  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4091  {
4092  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4093  }
4094  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4095  {
4096  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4097  }
4098  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4099  {
4100  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4101  }
4102  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4103  {
4104  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4105  }
4106  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4107  {
4108  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4109  }
4110  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4111  {
4112  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4113  }
4114  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4115  {
4116  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4117  }
4118  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4119  {
4120  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4121  }
4122  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4123  {
4124  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4125  }
4126  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4127  {
4128  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4129  }
4130  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4131  {
4132  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4133  }
4134  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4135  {
4136  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4137  }
4138  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4139  {
4140  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4141  }
4142  }
4143  // below added for version 0.6, only stop signals to be drawn
4144  else if(Next.TrackType == SignalPost)
4145  {
4146  for(int x = 0; x < 40; x++)
4147  {
4148  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4149  {
4150  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4151  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4152  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4153  int HOffset = 0;
4154  if(Next.SpeedTag > 73)
4155  {
4156  HOffset = 5;
4157  }
4158  else if(Next.SpeedTag == 71)
4159  {
4160  HOffset = 9;
4161  }
4162  int VOffset = 0;
4163  if(Next.SpeedTag == 69)
4164  {
4165  VOffset = 9;
4166  }
4167  else if(Next.SpeedTag == 72)
4168  {
4169  VOffset = 5;
4170  }
4171  else if(Next.SpeedTag == 74)
4172  {
4173  VOffset = 5;
4174  }
4175  Graphics::TBitmap *GraphicPtr;
4176  if(Next.SpeedTag > 71)
4177  {
4178  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4179  }
4180  else if(Next.SpeedTag < 70)
4181  {
4182  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4183  }
4184  else
4185  {
4186  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4187  }
4188  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4189  // plot special signal platform if present
4190  Graphics::TBitmap* SignalPlatformGraphic;
4191  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4192  {
4193  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4194  }
4195  // now plot signal (double yellow overwrites most of signal platform if present)
4196  // below amended for version 0.6
4198  {
4199  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4200  }
4201  else if(Next.SigAspect == TTrackElement::TwoAspect)
4202  {
4203  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4204  }
4205  else if(Next.SigAspect == TTrackElement::GroundSignal)
4206  {
4207  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4208  }
4209  else // 4 aspect
4210  {
4211  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4212  }
4213  break;
4214  }
4215  }
4216  }
4217  else
4218  {
4219  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4220  }
4221  }
4222  }
4223  if(OldTransparentColour != clB5G5R5)
4224  {
4225  Utilities->clTransparent = OldTransparentColour; // restore
4228  }
4229  Utilities->CallLogPop(1533);
4230 }
4231 
4232 // ---------------------------------------------------------------------------
4233 
4234 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4235 {
4236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4237  if(UserGraphicVector.empty())
4238  {
4239  Utilities->CallLogPop(2192);
4240  return;
4241  }
4242  else
4243  {
4244  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4245  {
4246  Bitmap->Canvas->CopyMode = cmSrcCopy;
4247  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4248  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4249  }
4250  }
4251  Utilities->CallLogPop(2193);
4252 }
4253 
4254 // ---------------------------------------------------------------------------
4255 
4256 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4257 /*
4258  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4259  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4260 */
4261 {
4262  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4263 // need to change graphics back to black on white if have a dark background
4264  TColor OldTransparentColour = Utilities->clTransparent;
4265 
4267  {
4268  Utilities->clTransparent = TColor(0xFFFFFF); // white
4271  }
4272  TTrackElement Next;
4273 
4274  Bitmap->Canvas->CopyMode = cmSrcCopy;
4276  Graphics::TBitmap *GraphicOutput;
4277 
4278  while(ReturnNextInactiveTrackElement(3, Next))
4279  {
4280  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4281  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4282  {
4283  if(Next.SpeedTag == 144) // level crossing
4284  {
4285  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4286  if(BaseElement == 1) // hor element
4287  {
4288  if(Next.Attribute == 1) // open to trains
4289  {
4290  GraphicOutput = RailGraphics->LCBothHor;
4291  }
4292  else // plot as closed to trains if in any other state
4293  {
4294  GraphicOutput = RailGraphics->LCBothVer;
4295  }
4296  }
4297  else // vert element
4298  {
4299  if(Next.Attribute == 1) // open to trains
4300  {
4301  GraphicOutput = RailGraphics->LCBothVer;
4302  }
4303  else // plot as closed to trains if in any other state
4304  {
4305  GraphicOutput = RailGraphics->LCBothHor;
4306  }
4307  }
4308  }
4309  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4310  }
4311  }
4312 
4313  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4314 
4315  NextTrackElementPtr = TrackVector.begin();
4316  while(ReturnNextTrackElement(3, Next))
4317  {
4318  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4319  {
4320  if(Next.TrackType == Points) // plot active fillet
4321  {
4322  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4323  if(Next.SpeedTag < 28)
4324  {
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4327  }
4328  else if(Next.SpeedTag < 132)
4329  {
4330  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4332  }
4333  else
4334  {
4335  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4337  }
4338  if(Next.Failed) //added at v2.13.0
4339  {
4340  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4342  }
4343 
4344  }
4345  else if(Next.TrackType == GapJump) // plot as connected
4346  {
4347  if(Next.SpeedTag == 88)
4348  {
4349  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4350  }
4351  else if(Next.SpeedTag == 89)
4352  {
4353  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4354  }
4355  else if(Next.SpeedTag == 90)
4356  {
4357  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4358  }
4359  else if(Next.SpeedTag == 91)
4360  {
4361  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4362  }
4363  else if(Next.SpeedTag == 92)
4364  {
4365  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4366  }
4367  else if(Next.SpeedTag == 93)
4368  {
4369  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4370  }
4371  else if(Next.SpeedTag == 94)
4372  {
4373  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4374  }
4375  else if(Next.SpeedTag == 95)
4376  {
4377  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4378  }
4379  }
4380  else if(Next.TrackType == SignalPost) //plot in correct colour
4381  {
4382  for(int x = 0; x < 40; x++)
4383  {
4384  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4385  {
4386  //plot blank first, then plot platform if present - (always not striped for operating railway)
4387  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4388  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4389  int HOffset = 0;
4390  if(Next.SpeedTag > 73)
4391  {
4392  HOffset = 5;
4393  }
4394  else if(Next.SpeedTag == 71)
4395  {
4396  HOffset = 9;
4397  }
4398  int VOffset = 0;
4399  if(Next.SpeedTag == 69)
4400  {
4401  VOffset = 9;
4402  }
4403  else if(Next.SpeedTag == 72)
4404  {
4405  VOffset = 5;
4406  }
4407  else if(Next.SpeedTag == 74)
4408  {
4409  VOffset = 5;
4410  }
4411  Graphics::TBitmap *GraphicPtr;
4412  if(Next.SpeedTag > 71)
4413  {
4414  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4415  }
4416  else if(Next.SpeedTag < 70)
4417  {
4418  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4419  }
4420  else
4421  {
4422  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4423  }
4424  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4425  // plot special signal platform if present
4426  Graphics::TBitmap* SignalPlatformGraphic;
4427  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4428  {
4429  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4430  }
4431  if(!Next.Failed)
4432  {
4433  // now plot signal (double yellow overwrites most of signal platform if present)
4434  // below amended for version 0.6
4436  {
4437  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4438  }
4439  else if(Next.SigAspect == TTrackElement::TwoAspect)
4440  {
4441  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4442  }
4443  else if(Next.SigAspect == TTrackElement::GroundSignal)
4444  {
4445  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4446  }
4447  else // 4 aspect
4448  {
4449  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4450  }
4451  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4452  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4453  {
4454  if(Next.SpeedTag == 68)
4455  {
4456  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4457  }
4458  if(Next.SpeedTag == 69)
4459  {
4460  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4461  }
4462  if(Next.SpeedTag == 70)
4463  {
4464  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4465  }
4466  if(Next.SpeedTag == 71)
4467  {
4468  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4469  }
4470  if(Next.SpeedTag == 72)
4471  {
4472  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4473  }
4474  if(Next.SpeedTag == 73)
4475  {
4476  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4477  }
4478  if(Next.SpeedTag == 74)
4479  {
4480  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4481  }
4482  if(Next.SpeedTag == 75)
4483  {
4484  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4485  }
4486  }
4487  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4488  {
4489  for(int x = 0; x < 40; x++)
4490  {
4491  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4492  {
4493  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4494  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4495  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4496  // plot special signal platform if present
4497  Graphics::TBitmap* SignalPlatformGraphic;
4498  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4499  {
4500  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4501  }
4502  // now plot signal
4503  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4504  break;
4505  }
4506  }
4507  }
4508  break;
4509  }
4510  else //added at v2.13.0
4511  {
4513  {
4514  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4515  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4516  }
4517  else
4518  {
4519  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4520  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4521  }
4522  break;
4523  }
4524  }
4525  }
4526  }
4527  else
4528  {
4529  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4530  if(Next.Failed) //added at v2.13.0
4531  {
4532  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4534  }
4535  }
4536  }
4537  }
4538  if(OldTransparentColour != clB5G5R5)
4539  {
4540  Utilities->clTransparent = OldTransparentColour; // restore
4543  }
4544  Utilities->CallLogPop(1701);
4545 }
4546 
4547 // ---------------------------------------------------------------------------
4548 
4549 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4550 {
4551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4552  for(unsigned int x = 0; x < TrackVector.size(); x++)
4553  {
4554  if(TrackElementAt(1093, x).TrackType == GapJump)
4555  {
4556  if(TrackElementAt(1094, x).Conn[0] > -1)
4557  {
4558  continue; // to next 'x' value as this element has already been set
4559  }
4560  // here if identify a GapJump element not yet set
4561  GapPos = x;
4562  GapHLoc = TrackElementAt(1095, x).HLoc;
4563  GapVLoc = TrackElementAt(1096, x).VLoc;
4564  // highlight it
4566  Utilities->CallLogPop(469);
4567  return(true);
4568  }
4569  }
4570  Utilities->CallLogPop(470);
4571  return(false);
4572 }
4573 
4574 // ---------------------------------------------------------------------------
4575 
4576 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4577 {
4578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4579  AnsiString(VLoc));
4580  int Position;
4581  TTrackElement TrackElement;
4582 
4583  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4584  {
4585  Utilities->CallLogPop(471);
4586  return(false); // not found
4587  }
4588  if(TrackElement.TrackType != GapJump)
4589  {
4590  Utilities->CallLogPop(472);
4591  return(false); // found something but not a gap
4592  }
4593  if(Position == GapPos)
4594  {
4595  Utilities->CallLogPop(473);
4596  return(false); // selected original gap
4597  }
4598  if(TrackElementAt(1097, Position).Conn[0] != -1)
4599  {
4600  Utilities->CallLogPop(474);
4601  return(false); // already selected
4602  }
4603  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4604  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4605  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4606  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4607 // now highlight the selected location
4608  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4609  Utilities->CallLogPop(475);
4610  return(true);
4611 }
4612 
4613 // ---------------------------------------------------------------------------
4614 
4615 bool TTrack::GapsUnset(int Caller)
4616 // returns true if there are gaps and any are unset
4617 {
4618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4619  if(TrackVector.size() == 0)
4620  {
4621  Utilities->CallLogPop(476);
4622  return(false);
4623  }
4624  for(unsigned int x = 0; x < TrackVector.size(); x++)
4625  {
4626  if(TrackElementAt(1102, x).TrackType == GapJump)
4627  {
4628  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4629  {
4630  Utilities->CallLogPop(477);
4631  return(true);
4632  }
4633  else // set, but may not have matching element, or that element may not be set
4634  {
4635  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4636  // check that the element pointed to by the gap link is a GapJump
4637  {
4638  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4639  Utilities->CallLogPop(1137);
4640  return(false);
4641  }
4642 // here if gap connection is itself a GapJump
4643  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4644  // check that the element pointed to by the gap link is a GapJump & that its gap link
4645  // points back to 'x'
4646  {
4647  Utilities->CallLogPop(478);
4648  return(true);
4649  }
4650 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4651  }
4652  } // if(TrackElementAt(, x).TrackType == GapJump)
4653 
4654  } // for x...
4655  Utilities->CallLogPop(479);
4656  return(false);
4657 }
4658 
4659 // ---------------------------------------------------------------------------
4660 
4661 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4662 {
4663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4664  for(unsigned int x = 0; x < TrackVector.size(); x++)
4665  {
4666  if(TrackElementAt(1110, x).TrackType == GapJump)
4667  {
4668  Utilities->CallLogPop(1105);
4669  return(false);
4670  }
4671  }
4672  Utilities->CallLogPop(1106);
4673  return(true);
4674 }
4675 
4676 // ---------------------------------------------------------------------------
4677 
4678 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4679 {
4680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4681  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4682  {
4683  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4684  {
4685  Utilities->CallLogPop(1107);
4686  return(false);
4687  }
4688  }
4689  for(unsigned int x = 0; x < TrackVector.size(); x++)
4690  {
4691  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4692  {
4693  Utilities->CallLogPop(1108);
4694  return(false);
4695  }
4696  }
4697  Utilities->CallLogPop(1109);
4698  return(true);
4699 }
4700 
4701 // ---------------------------------------------------------------------------
4702 
4704 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4705 // returns false otherwise or if there are no NamedLocationElements
4706 {
4707  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4708  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4709  {
4710  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4711  {
4712  if(InactiveTrackElementAt(139, x).LocationName == "")
4713  {
4714  Utilities->CallLogPop(1110);
4715  return(true);
4716  }
4717  }
4718  }
4719  for(unsigned int x = 0; x < TrackVector.size(); x++)
4720  {
4721  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4722  {
4723  if(TrackElementAt(1113, x).LocationName == "")
4724  {
4725  Utilities->CallLogPop(1111);
4726  return(true);
4727  }
4728  }
4729  }
4730  Utilities->CallLogPop(1112);
4731  return(false);
4732 }
4733 
4734 // ---------------------------------------------------------------------------
4735 
4736 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4737 {
4738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4739  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4740  Utilities->CallLogPop(480);
4741 }
4742 
4743 // ---------------------------------------------------------------------------
4744 
4746 {
4747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4748  if(TrackVector.size() == 0)
4749  {
4750  Utilities->CallLogPop(481);
4751  return;
4752  }
4753  for(unsigned int x = 0; x < TrackVector.size(); x++)
4754  {
4755  if(TrackElementAt(1114, x).TrackType == GapJump)
4756  {
4757  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4758  {
4759  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4760  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4761  {
4762  TrackElementAt(1118, x).Conn[0] = -1;
4763  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4764  continue; // to next 'x'
4765  }
4766 // here if gap connection is itself a GapJump
4767  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4768  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4769  // if not clear Conns & CLks
4770  {
4771  TrackElementAt(1121, x).Conn[0] = -1;
4772  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4773  continue; // to next 'x'
4774  }
4775 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4776 // hence no more action needed on these Conns & CLks
4777  }
4778  } // else //gap jump
4779 
4780  } // for x...
4781 // throw Exception("Test Exception");//test
4782  Utilities->CallLogPop(482);
4783 }
4784 
4785 // ---------------------------------------------------------------------------
4786 
4787 void TTrack::ResetSignals(int Caller)
4788 {
4789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4790  for(unsigned int x = 0; x < TrackVector.size(); x++)
4791  {
4792  if(TrackElementAt(1123, x).TrackType == SignalPost)
4793  {
4794  TrackElementAt(1124, x).Attribute = 0;
4795  TrackElementAt(1514, x).Failed = false;
4796  TrackElementAt(1682, x).CallingOnSet = false; //added at v2.20.3 to clear position light signals
4797  }
4798  }
4799  FailedSignalsVector.clear();
4800  Utilities->CallLogPop(483);
4801 }
4802 
4803 // ---------------------------------------------------------------------------
4804 
4805 void TTrack::ResetPoints(int Caller)
4806 {
4807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4808  for(unsigned int x = 0; x < TrackVector.size(); x++)
4809  {
4810  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4811  {
4812  TrackElementAt(1126, x).Attribute = 0;
4813  TrackElementAt(1515, x).Failed = false;
4816  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4817  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4818  }
4819  }
4820  FailedPointsVector.clear();
4821  Utilities->CallLogPop(484);
4822 }
4823 
4824 // ---------------------------------------------------------------------------
4825 
4826 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4827 {
4828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4829  for(unsigned int x = 0; x < TrackVector.size(); x++)
4830  {
4831  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4832  {
4833  TrackElementAt(1556, x).Failed = false;
4835  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4836  }
4837  }
4838  TSRVector.clear();
4839  Utilities->CallLogPop(2550);
4840 }
4841 
4842 // ---------------------------------------------------------------------------
4843 
4844 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4845 {
4846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4847  if(TrackVector.empty())
4848  {
4849  TrackMap.clear();
4850  Utilities->CallLogPop(485);
4851  return(true);
4852  }
4853 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4854  THVPair TrackMapKeyPair;
4855 
4856  NewVector.clear();
4857  TTrackMapIterator TrackMapPtr;
4858 
4859  if(!TrackMap.empty())
4860  {
4861  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4862  {
4863  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4864  }
4865  }
4866  if(NewVector.size() != TrackMap.size())
4867  {
4868  throw Exception("Error - Map & Vector different sizes");
4869  }
4870  unsigned int NonZeroCount = 0;
4871 
4872  for(unsigned int x = 0; x < TrackVector.size(); x++)
4873  {
4874  if(TrackElementAt(1127, x).TrackType != Erase)
4875  {
4876  NonZeroCount++;
4877  }
4878  }
4879  if(NewVector.size() != NonZeroCount)
4880  {
4881  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4882  }
4884  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4885  TTrackMapEntry TrackMapEntry;
4886 
4887  for(unsigned int x = 0; x < TrackVector.size(); x++)
4888  {
4889  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4890  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4891  TrackMapEntry.first = TrackMapKeyPair;
4892  TrackMapEntry.second = x;
4893  if(!(TrackMap.insert(TrackMapEntry).second))
4894  {
4895  throw Exception("Error - map insertion failure, TrackVector in error");
4896  }
4897  }
4898 // All track now relocated in TrackVector, reset all Conns & CLks
4899  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4900  {
4901  for(unsigned int y = 0; y < 4; y++)
4902  {
4903  TrackElementAt(1130, x).Conn[y] = -1;
4904  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4905  }
4906  }
4907  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4908  CheckMapAndTrack(4); // test
4909  CheckMapAndInactiveTrack(4); // test
4910  CheckLocationNameMultiMap(8); // test
4911  if(!ResetGapsFromGapMap(1))
4912  {
4913  Utilities->CallLogPop(489);
4914  return(false);
4915  }
4916  Utilities->CallLogPop(490);
4917  return(true);
4918 }
4919 
4920 // ---------------------------------------------------------------------------
4921 
4922 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4923 {
4924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4925  GapMap.clear();
4926  THVPair GapMapKeyPair, GapMapValuePair;
4927  TGapMapEntry GapMapEntry;
4928 
4929  for(unsigned int x = 0; x < TrackVector.size(); x++)
4930  {
4931  if(TrackElementAt(1132, x).TrackType == GapJump)
4932  {
4933  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4934  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4935  GapMapEntry.first = GapMapKeyPair;
4936  if(TrackElementAt(1135, x).Conn[0] == -1)
4937  {
4938  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4939  }
4940  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4941  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4942  GapMapEntry.second = GapMapValuePair;
4943  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4944  {
4945  GapMap.insert(GapMapEntry);
4946  }
4947  }
4948  }
4949  Utilities->CallLogPop(492);
4950 }
4951 
4952 // ---------------------------------------------------------------------------
4953 
4954 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4955 {
4956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4957 
4958 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4959  LocError = false;
4960  bool TrackElementPositionsOK = true;
4961 
4962  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4963  {
4964  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4965  {
4966  continue; // skip blank elements
4967  }
4968 // check footcrossing linkages
4969  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4970  {
4971  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4972  {
4973  ShowMessage(
4974  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4975  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4976  "can't connect to an underpass or vice versa)");
4977  HLoc = TrackElementAt(1141, x).HLoc;
4978  VLoc = TrackElementAt(1142, x).VLoc;
4979  LocError = true;
4980  Utilities->CallLogPop(493);
4981  return(false);
4982  }
4983  }
4984  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4985  {
4986  if(TrackElementAt(1143, x).Link[y] <= 0)
4987  {
4988  continue; // no link
4989  }
4990  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4991  {
4992  continue; // buffer
4993  }
4994  if(TrackElementAt(1146, x).Config[y] == Gap)
4995  {
4996  continue; // gaps set later from GapMap
4997  }
4998  // get required H & V for track element joining link 'y'
4999  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
5000  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
5001  // find track element if present
5002  bool ConnectionFoundFlag;
5003  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
5004  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5005  {
5006  ShowMessage("Can't have a track element adjacent to a continuation exit");
5007  HLoc = TrackElementAt(1152, x).HLoc;
5008  VLoc = TrackElementAt(1153, x).VLoc;
5009  LocError = true;
5010  if(FinalCall)
5011  {
5012  throw Exception("Error in final track linkage - continuation adjacent to another element");
5013  }
5014  Utilities->CallLogPop(1539);
5015  return(false);
5016  }
5017  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
5018  {
5019  continue;
5020  }
5021  if(ConnectionFoundFlag)
5022  {
5023  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
5024  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
5025 
5026  bool ExitSignal = false;
5027  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
5028  {
5029  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
5030  {
5031  ExitSignal = true;
5032  }
5033  }
5034  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5035  {
5036  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5037  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5038  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5039  TrackElementPositionsOK = false;
5040  }
5041  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5042  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5043  {
5044  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5045  // need room for a train (2 elements) without fouling points or signals
5046  TrackElementPositionsOK = false;
5047  }
5048  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5049  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5050  {
5051  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5052  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5053  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5054  // be named but needs the adjacent element named too
5055  TrackElementPositionsOK = false;
5056  }
5057  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5058  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5059  {
5060  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5061  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5062  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5063  TrackElementPositionsOK = false;
5064  }
5065 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5066 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage)
5067  {
5068  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5069  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5070  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5071  TrackElementPositionsOK = false;
5072  }*/
5073  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5074  {
5075  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5076  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5077  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5078  TrackElementPositionsOK = false;
5079  }
5080  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5081  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5082  {
5083  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5084  TrackElementPositionsOK = false;
5085  }
5086  // if failed then set the invert values for the offending element
5087  if(!TrackElementPositionsOK)
5088  {
5089  HLoc = TrackElementAt(1183, x).HLoc;
5090  VLoc = TrackElementAt(1184, x).VLoc;
5091  LocError = true;
5092  if(FinalCall)
5093  {
5094  throw Exception("Error in track element positions in FinalCall");
5095  }
5096  Utilities->CallLogPop(494);
5097  return(false);
5098  }
5099  }
5100  // no 'else' here, if there's no link then will be picked up in 2nd pass
5101  }
5102  } // for(unsigned int x=0;x<TrackVector.size();x++)
5103 
5104 
5105 //2nd pass - looking for missing connections
5106  LocError = false;
5107  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5108  {
5109  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5110  {
5111  continue; // skip blank elements
5112  }
5113  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5114  {
5115  if(TrackElementAt(1440, x).Link[y] <= 0)
5116  {
5117  continue; // no link
5118  }
5119  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5120  {
5121  continue; // buffer
5122  }
5123  if(TrackElementAt(1443, x).Config[y] == Gap)
5124  {
5125  continue; // gaps set later from GapMap
5126  }
5127  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5128  {
5129  continue; //continuation
5130  }
5131  // get required H & V for track element joining link 'y'
5132  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5133  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5134  // find track element if present
5135  bool ConnectionFoundFlag;
5136  bool LinkMatchFound = false;
5137  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5138  // if there isn't a connection set the invert values for the offending element
5139  if(ConnectionFoundFlag) //set the ConnLinkPos values
5140  {
5141  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5142  {
5143  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5144  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5145  {
5146  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5147  LinkMatchFound = true;
5148  break; //can only match 1 so can break
5149  }
5150  }
5151  if(!LinkMatchFound)
5152  {
5153  HLoc = TrackElementAt(1446, x).HLoc;
5154  VLoc = TrackElementAt(1447, x).VLoc;
5155  LocError = true;
5156  if(FinalCall)
5157  {
5158  throw Exception("Error in final track linkage - - no matching link found");
5159  }
5160  Utilities->CallLogPop(495);
5161  return(false);
5162  }
5163  }
5164  else //error
5165  {
5166  HLoc = TrackElementAt(1185, x).HLoc;
5167  VLoc = TrackElementAt(1186, x).VLoc;
5168  LocError = true;
5169  if(FinalCall)
5170  {
5171  throw Exception("Error in final track linkage - connection not found");
5172  }
5173  Utilities->CallLogPop(2443);
5174  return(false);
5175  }
5176  }
5177  }
5178 //end of 2nd pass
5179 
5180  if(FinalCall)
5181  {
5184  }
5185 
5186 // confirmatiory checks that all ok - or throw error
5187  bool ConnErrorFlag = false;
5188 
5189  for(unsigned int x = 0; x < TrackVector.size(); x++)
5190  {
5191  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5192  {
5193  ConnErrorFlag = true;
5194  }
5195  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5196  {
5197  ConnErrorFlag = true;
5198  }
5199  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5200  {
5201  ConnErrorFlag = true;
5202  }
5203  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5204  {
5205  ConnErrorFlag = true;
5206  }
5207  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5208  {
5209  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5210  {
5211  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5212  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5213  {
5214  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5215  }
5216  }
5217  }
5218  }
5219  if(ConnErrorFlag)
5220  {
5221  if(FinalCall)
5222  {
5223  throw Exception("ConnError in LinkTrack - Final");
5224  }
5225  else
5226  {
5227  throw Exception("ConnError in LinkTrack - Precheck");
5228  }
5229  }
5230  bool CLkErrorFlag = false;
5231 
5232  for(unsigned int x = 0; x < TrackVector.size(); x++)
5233  {
5234  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5235  {
5236  CLkErrorFlag = true;
5237  }
5238  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5239  {
5240  CLkErrorFlag = true;
5241  }
5242  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5243  {
5244  CLkErrorFlag = true;
5245  }
5246  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5247  {
5248  CLkErrorFlag = true;
5249  }
5250  }
5251 
5252  if(CLkErrorFlag)
5253  {
5254  if(FinalCall)
5255  {
5256  throw Exception("CLkError in LinkTrack - Final");
5257  }
5258  else
5259  {
5260  throw Exception("CLkError in LinkTrack - Precheck");
5261  }
5262  }
5263 
5264 // set element lengths to min of 10m
5265  for(unsigned int x = 0; x < TrackVector.size(); x++)
5266  {
5267  if(TrackElementAt(1214, x).TrackType == Erase)
5268  {
5269  continue; // skip blank elements
5270  }
5271  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5272  {
5273  TrackElementAt(1216, x).Length01 = 10;
5274  }
5275  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5276  {
5277  TrackElementAt(1219, x).Length23 = 10;
5278  }
5279  }
5280 
5281  if(FinalCall) // ONLY at FinalCall, no point calling twice
5282  {
5283  CalcHLocMinEtc(3);
5284  }
5285 
5286  Utilities->CallLogPop(497);
5287  return(true);
5288 }
5289 
5290 // ---------------------------------------------------------------------------
5291 
5292 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5293 {
5294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5295  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5296  {
5297  if(TrackElementAt(1220, x).TrackType == Erase)
5298  {
5299  continue; // skip blank elements
5300 
5301  }
5302 // check footcrossing linkages
5303  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5304  {
5305  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5306  {
5307  Utilities->CallLogPop(1127);
5308  return(false);
5309  }
5310  }
5311  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5312  {
5313  if(TrackElementAt(1223, x).Link[y] <= 0)
5314  {
5315  continue; // no link
5316  }
5317  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5318  {
5319  continue; // buffer
5320  }
5321  if(TrackElementAt(1226, x).Config[y] == Gap)
5322  {
5323  continue; // gaps set later from GapMap
5324 
5325  }
5326  // get required H & V for track element joining link 'y'
5327  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5328  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5329  // find track element if present
5330  bool ConnectionFoundFlag;
5331  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5332  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5333  {
5334  if(FinalCall)
5335  {
5336  throw Exception("Error in final track linkage - continuation adjacent to another element");
5337  }
5338  Utilities->CallLogPop(1540);
5339  return(false);
5340  }
5341  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5342  {
5343  continue;
5344  }
5345  if(ConnectionFoundFlag)
5346  {
5347  TrackElementAt(1234, x).Conn[y] = VecPos;
5348  bool LinkFoundFlag = false;
5349  // find connecting link in the newly found track element if there is one & make checks
5350  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5351  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5352  {
5353  Utilities->CallLogPop(1541);
5354  return(false);
5355  }
5356  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5357  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5358  {
5359  Utilities->CallLogPop(1542);
5360  return(false);
5361  }
5362  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5363  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5364  {
5365  Utilities->CallLogPop(1543);
5366  return(false);
5367  }
5368  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5369  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5370  {
5371  Utilities->CallLogPop(1981);
5372  return(false);
5373  }
5374 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5375  else if(TrackElementAt(, x).TrackType == Continuation)
5376  {
5377  int H = TrackElementAt(, x).HLoc;
5378  int V = TrackElementAt(, x).VLoc;
5379  bool FoundFlag = false;
5380  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5381  if(FoundFlag)
5382  {
5383  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5384  {
5385  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5386  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5387  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5388  if(FoundFlag)
5389  {
5390  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5391  {
5392  Utilities->CallLogPop();
5393  return false;
5394  }
5395  }
5396  else
5397  {
5398  Utilities->CallLogPop();
5399  return false;
5400  }
5401  }
5402  }
5403  }
5404 */
5405  for(unsigned int a = 0; a < 4; a++)
5406  {
5407  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5408  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5409  {
5410  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5411  // note - this ensures that if the connecting element is a leading point
5412  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5413  // (Points have the same link value for both [0] and [2])
5414  LinkFoundFlag = true;
5415  break; // stop after first find or will find later link for leading point
5416  }
5417  }
5418  if(!LinkFoundFlag)
5419  {
5420  if(FinalCall)
5421  {
5422  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5423  }
5424  Utilities->CallLogPop(1128);
5425  return(false);
5426  }
5427  }
5428  else // if(ConnectionFoundFlag)
5429  {
5430  if(FinalCall)
5431  {
5432  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5433  }
5434  Utilities->CallLogPop(1129);
5435  return(false);
5436  }
5437  }
5438  } // for(unsigned int x=0;x<TrackVector.size();x++)
5439 
5440  if(FinalCall)
5441  {
5444  }
5445 // final check
5446  bool ConnErrorFlag = false;
5447 
5448  for(unsigned int x = 0; x < TrackVector.size(); x++)
5449  {
5450  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5451  {
5452  ConnErrorFlag = true;
5453  }
5454  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5455  {
5456  ConnErrorFlag = true;
5457  }
5458  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5459  {
5460  ConnErrorFlag = true;
5461  }
5462  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5463  {
5464  ConnErrorFlag = true;
5465  }
5466  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5467  {
5468  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5469  {
5470  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5471  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5472  {
5473  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5474  }
5475  }
5476  }
5477  }
5478  if(ConnErrorFlag)
5479  {
5480  if(FinalCall)
5481  {
5482  throw Exception("ConnError in LinkTrack - Final");
5483  }
5484  else
5485  {
5486  throw Exception("ConnError in LinkTrack - Precheck");
5487  }
5488  }
5489  bool CLkErrorFlag = false;
5490 
5491  for(unsigned int x = 0; x < TrackVector.size(); x++)
5492  {
5493  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5494  {
5495  CLkErrorFlag = true;
5496  }
5497  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5498  {
5499  CLkErrorFlag = true;
5500  }
5501  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5502  {
5503  CLkErrorFlag = true;
5504  }
5505  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5506  {
5507  CLkErrorFlag = true;
5508  }
5509  }
5510 
5511  if(CLkErrorFlag)
5512  {
5513  if(FinalCall)
5514  {
5515  throw Exception("CLkError in LinkTrack - Final");
5516  }
5517  else
5518  {
5519  throw Exception("CLkError in LinkTrack - Precheck");
5520  }
5521  }
5522 // set element lengths to min of 10m
5523  for(unsigned int x = 0; x < TrackVector.size(); x++)
5524  {
5525  if(TrackElementAt(1284, x).TrackType == Erase)
5526  {
5527  continue; // skip blank elements
5528  }
5529  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5530  {
5531  TrackElementAt(1286, x).Length01 = 10;
5532  }
5533  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5534  {
5535  TrackElementAt(1289, x).Length23 = 10;
5536  }
5537  }
5538 
5539  if(FinalCall) // ONLY at FinalCall, no point calling twice
5540  {
5541  CalcHLocMinEtc(7);
5542  }
5543  Utilities->CallLogPop(1130);
5544  return(true);
5545 }
5546 
5547 // ---------------------------------------------------------------------------
5548 
5549 bool TTrack::IsTrackLinked(int Caller) // not used any more
5550 {
5551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5552  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5553  {
5554  if(TrackElementAt(1290, x).TrackType == Erase)
5555  {
5556  Utilities->CallLogPop(498);
5557  return(false);
5558  }
5559 // check foot linkages
5560  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5561  {
5562  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5563  {
5564  Utilities->CallLogPop(499);
5565  return(false);
5566  }
5567  }
5568  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5569  {
5570  if(TrackElementAt(1293, x).Link[y] <= 0)
5571  {
5572  continue; // no link
5573  }
5574  if(TrackElementAt(1294, x).Config[y] == End)
5575  {
5576  continue; // buffer or continuation
5577  }
5578  if(TrackElementAt(1295, x).Config[y] == Gap)
5579  {
5580  continue; // gaps set later from GapMap
5581 
5582  }
5583  // get required H & V for track element joining link 'y'
5584  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5585  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5586  // find track element if present
5587  bool ConnectionFoundFlag = false;
5588  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5589  if(ConnectionFoundFlag)
5590  {
5591  TrackElementAt(1300, x).Conn[y] = VecPos;
5592  // find connecting link in the newly found track element if there is one & make buffer check
5593  bool LinkFoundFlag = false;
5594  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5595  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5596  {
5597  Utilities->CallLogPop(500);
5598  return(false);
5599  }
5600  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5601  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5602  {
5603  Utilities->CallLogPop(501);
5604  return(false);
5605  }
5606  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5607  {
5608  Utilities->CallLogPop(502);
5609  return(false);
5610  }
5611  else
5612  {
5613  for(unsigned int a = 0; a < 4; a++)
5614  {
5615  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5616  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5617  {
5618  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5619  // note - this ensures that if the connecting element is a leading point
5620  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5621  // (Points have the same link value for both [0] and [2])
5622  LinkFoundFlag = true;
5623  break; // stop after first find or will find later link for leading point
5624  }
5625  }
5626  }
5627  if(!LinkFoundFlag)
5628  {
5629  Utilities->CallLogPop(503);
5630  return(false);
5631  }
5632  }
5633  else // if(ConnectionFoundFlag)
5634  {
5635  Utilities->CallLogPop(504);
5636  return(false);
5637  }
5638  }
5639  } // for(unsigned int x=0;x<TrackVector.size();x++)
5640 
5641 // final check
5642  bool ConnErrorFlag = false;
5643 
5644  for(unsigned int x = 0; x < TrackVector.size(); x++)
5645  {
5646  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5647  {
5648  ConnErrorFlag = true;
5649  }
5650  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5651  {
5652  ConnErrorFlag = true;
5653  }
5654  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5655  {
5656  ConnErrorFlag = true;
5657  }
5658  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5659  {
5660  ConnErrorFlag = true;
5661  }
5662  }
5663  if(ConnErrorFlag)
5664  {
5665  Utilities->CallLogPop(505);
5666  return(false);
5667  }
5668  bool CLkErrorFlag = false;
5669 
5670  for(unsigned int x = 0; x < TrackVector.size(); x++)
5671  {
5672  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5673  {
5674  CLkErrorFlag = true;
5675  }
5676  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5677  {
5678  CLkErrorFlag = true;
5679  }
5680  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5681  {
5682  CLkErrorFlag = true;
5683  }
5684  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5685  {
5686  CLkErrorFlag = true;
5687  }
5688  }
5689 
5690  if(CLkErrorFlag)
5691  {
5692  Utilities->CallLogPop(506);
5693  return(false);
5694  }
5695  Utilities->CallLogPop(507);
5696  return(true);
5697 }
5698 
5699 // ---------------------------------------------------------------------------
5700 
5702 {
5703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5704  int Position1, Position2;
5705  TTrackElement TrackElement1, TrackElement2;
5706  TGapMapIterator GapMapPtr;
5707 
5708  if(!GapMap.empty())
5709  {
5710  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5711  {
5712  int HLoc1 = GapMapPtr->first.first;
5713  int VLoc1 = GapMapPtr->first.second;
5714  int HLoc2 = GapMapPtr->second.first;
5715  int VLoc2 = GapMapPtr->second.second;
5716  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5717  {
5718  throw Exception("Failed to find H & V for gap1, GapMap in error");
5719  }
5720  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5721  {
5722  throw Exception("Failed to find H & V for gap2, GapMap in error");
5723  }
5724  if(TrackElementAt(9, Position1).TrackType != GapJump)
5725  {
5726  throw Exception("Element at Pos1 not a gap, GapMap in error");
5727  }
5728  if(TrackElementAt(10, Position2).TrackType != GapJump)
5729  {
5730  throw Exception("Element at Pos2 not a gap, GapMap in error");
5731  }
5732  TrackElementAt(11, Position1).Conn[0] = Position2;
5733  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5734  TrackElementAt(13, Position2).Conn[0] = Position1;
5735  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5736  }
5737  }
5738  Utilities->CallLogPop(510);
5739  return(true);
5740 }
5741 
5742 // ---------------------------------------------------------------------------
5743 
5744 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5745 {
5746 // TIMPair MapEntry;
5747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5748  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5749  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5750  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5751  TLocationNameMultiMapEntry LocationNameEntry;
5752 
5753  LocationNameEntry.first = TrackElement.LocationName;
5754  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5755  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5756  {
5757 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5758 // could arise when loading old railways with multiple NonStationNamedLocs
5759  bool FoundFlag = false;
5760  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5761  if(FoundFlag)
5762  {
5763  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5764  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5765  {
5766  Utilities->CallLogPop(1813);
5767  return;
5768  }
5769  }
5770  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5771  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5772  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5773  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5774  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5775  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5776  if(TrackElement.FixedNamedLocationElement)
5777  {
5778  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5779  LocationNameMultiMap.insert(LocationNameEntry);
5780  }
5781  if(TrackElement.HLoc < HLocMin)
5782  {
5783  HLocMin = TrackElement.HLoc;
5784  }
5785  if(TrackElement.HLoc > HLocMax)
5786  {
5787  HLocMax = TrackElement.HLoc;
5788  }
5789  if(TrackElement.VLoc < VLocMin)
5790  {
5791  VLocMin = TrackElement.VLoc;
5792  }
5793  if(TrackElement.VLoc > VLocMax)
5794  {
5795  VLocMax = TrackElement.VLoc;
5796  }
5797  }
5798  else
5799  {
5800 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5801 // shouldn't arise but leave in as a safeguard
5802  bool FoundFlag = false;
5803  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5804  if(FoundFlag)
5805  {
5806  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5807  {
5808  Utilities->CallLogPop(1814);
5809  return;
5810  }
5811  }
5812  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5813  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5814  {
5815  TrackMapKeyPair.first = TrackElement.HLoc;
5816  TrackMapKeyPair.second = TrackElement.VLoc;
5817  TrackMapEntry.first = TrackMapKeyPair;
5818  TrackMapEntry.second = TrackVector.size() - 1;
5819  TrackMap.insert(TrackMapEntry);
5820  if(TrackElement.FixedNamedLocationElement)
5821  {
5822  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5823  LocationNameMultiMap.insert(LocationNameEntry);
5824  }
5825  if(TrackElement.HLoc < HLocMin)
5826  {
5827  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5828  }
5829  if(TrackElement.HLoc > HLocMax)
5830  {
5831  HLocMax = TrackElement.HLoc;
5832  }
5833  if(TrackElement.VLoc < VLocMin)
5834  {
5835  VLocMin = TrackElement.VLoc;
5836  }
5837  if(TrackElement.VLoc > VLocMax)
5838  {
5839  VLocMax = TrackElement.VLoc;
5840  }
5841  }
5842  }
5843 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5844 // CheckMapAndInactiveTrack(6);//test
5845 
5846 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5847 // with the Platforms until layout fully loaded
5848  Utilities->CallLogPop(511);
5849 }
5850 
5851 // ---------------------------------------------------------------------------
5852 
5853 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5854 {
5855  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5856  AnsiString(VLoc));
5857  THVPair TrackMapKeyPair;
5858 
5859  FoundFlag = false;
5860  TTrackMapIterator TrackMapPtr;
5861 
5862  TrackMapKeyPair.first = HLoc;
5863  TrackMapKeyPair.second = VLoc;
5864  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5865  if(TrackMapPtr == TrackMap.end())
5866  {
5867  Utilities->CallLogPop(512);
5868  return(-1); // nothing found
5869  }
5870  else
5871  {
5872  FoundFlag = true;
5873  Utilities->CallLogPop(513);
5874  return(TrackMapPtr->second);
5875  }
5876 }
5877 
5878 // ---------------------------------------------------------------------------
5879 
5880 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5881 {
5882  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5883  AnsiString(VLoc));
5884  THVPair TrackMapKeyPair;
5885  TTrackMapIterator TrackMapPtr;
5886 
5887  TrackMapKeyPair.first = HLoc;
5888  TrackMapKeyPair.second = VLoc;
5889  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5890  if(TrackMapPtr == TrackMap.end())
5891  {
5892  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5893  throw Exception(Message);
5894  }
5895  else
5896  {
5897  Utilities->CallLogPop(1943);
5898  return(TrackElementAt(871, TrackMapPtr->second));
5899  }
5900 }
5901 
5902 // ---------------------------------------------------------------------------
5903 
5904 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5905 { //modded at v2.9.2 to make Map & Vector references
5906  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5907  AnsiString(VLoc));
5908  THVPair MapKeyPair;
5909  TTrackMapIterator MapPtr;
5910 
5911  MapKeyPair.first = HLoc;
5912  MapKeyPair.second = VLoc;
5913  MapPtr = Map.find(MapKeyPair);
5914  if(MapPtr == Map.end())
5915  {
5916  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5917  throw Exception(Message);
5918  }
5919  else
5920  {
5921  Utilities->CallLogPop(2280);
5922  return(Vector.at(MapPtr->second));
5923  }
5924 }
5925 
5926 // ---------------------------------------------------------------------------
5927 
5929 {
5930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5931  AnsiString(VLoc));
5932  THVPair InactiveTrackMapKeyPair;
5933  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5934 
5935  InactiveTrackMapKeyPair.first = HLoc;
5936  InactiveTrackMapKeyPair.second = VLoc;
5937  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5938  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5939  {
5940  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5941  throw Exception(Message);
5942  }
5943  else
5944  {
5945  Utilities->CallLogPop(1949);
5946  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5947  }
5948 }
5949 
5950 // ---------------------------------------------------------------------------
5951 
5952 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5953 {
5954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5955  bool Present = true;
5956  THVPair TrackMapKeyPair;
5957  TTrackMapIterator TrackMapPtr;
5958 
5959  TrackMapKeyPair.first = HLoc;
5960  TrackMapKeyPair.second = VLoc;
5961  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5962  if(TrackMapPtr == TrackMap.end())
5963  {
5964  Present = false;
5965  }
5966  Utilities->CallLogPop(2057);
5967  return(Present);
5968 }
5969 
5970 // ---------------------------------------------------------------------------
5971 
5972 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5973 {
5974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5975  AnsiString(VLoc));
5976  bool Present = true;
5977  THVPair InactiveTrackMapKeyPair;
5978  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5979 
5980  InactiveTrackMapKeyPair.first = HLoc;
5981  InactiveTrackMapKeyPair.second = VLoc;
5982  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5983  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5984  {
5985  Present = false;
5986  }
5987  Utilities->CallLogPop(2058);
5988  return(Present);
5989 }
5990 
5991 // ---------------------------------------------------------------------------
5992 
5993 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5994 // max number of elements is 2, for platforms
5995 // note that both elements of RetPair may be the same, if only one present in map
5996 {
5997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5998  AnsiString(VLoc));
5999  THVPair InactiveTrackMapKeyPair;
6000  TIMPair RetPair;
6001  TInactiveTrackRange InactiveTrackRange;
6002 
6003  FoundFlag = false;
6004  InactiveTrackMapKeyPair.first = HLoc;
6005  InactiveTrackMapKeyPair.second = VLoc;
6006  if(InactiveTrack2MultiMap.empty())
6007  {
6008  RetPair.first = 0;
6009  RetPair.second = 0;
6010  Utilities->CallLogPop(1815);
6011  return(RetPair); // map empty
6012  }
6013  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
6014  if(InactiveTrackRange.first == InactiveTrackRange.second)
6015  {
6016  RetPair.first = 0;
6017  RetPair.second = 0;
6018  Utilities->CallLogPop(514);
6019  return(RetPair); // nothing found
6020  }
6021  else
6022  {
6023  RetPair.first = InactiveTrackRange.first->second;
6024  RetPair.second = (--InactiveTrackRange.second)->second;
6025  FoundFlag = true;
6026  Utilities->CallLogPop(515);
6027  return(RetPair);
6028  }
6029 }
6030 
6031 // ---------------------------------------------------------------------------
6032 
6033 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6034 {
6035 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6036  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6037  AnsiString(DivergingPosition));
6038  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6039  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6040  int SpeedTag1 = T1.SpeedTag;
6041  int SpeedTag2 = T2.SpeedTag;
6042 
6043  if((T1.Attribute) != (T2.Attribute))
6044  {
6045  Utilities->CallLogPop(516);
6046  return(false);
6047  }
6048  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6049  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6050  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6051  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6052  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6053  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6054  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6055  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6056  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6057  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6058  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6059  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6060  {
6061  Utilities->CallLogPop(517);
6062  return(true);
6063  }
6064  else
6065  {
6066  Utilities->CallLogPop(518);
6067  return(false);
6068  }
6069 }
6070 
6071 // ---------------------------------------------------------------------------
6072 
6073 /*
6074  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6075  {
6076  if(lower.second < higher.second) return true;
6077  else if(lower.second > higher.second) return false;
6078  else if(lower.second == higher.second)
6079  {
6080  if(lower.first < higher.first) return true;
6081  }
6082  return false;
6083  }
6084 */
6085 // ---------------------------------------------------------------------------
6086 
6087 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6088 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6089 {
6090  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6091  if(TrackElement.TrackType != GapJump)
6092  {
6093  throw Exception("Error, Wrong track type in PlotGap");
6094  }
6095  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6096  {
6097  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6098  }
6099  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6100  {
6101  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6102  }
6103  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6104  {
6105  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6106  }
6107  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6108  {
6109  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6110  }
6111  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6112  {
6113  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6114  }
6115  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6116  {
6117  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6118  }
6119  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6120  {
6121  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6122  }
6123  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6124  {
6125  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6126  }
6127  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6128  {
6129  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6130  }
6131  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6132  {
6133  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6134  }
6135  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6136  {
6137  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6138  }
6139  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6140  {
6141  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6142  }
6143  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6144  {
6145  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6146  }
6147  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6148  {
6149  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6150  }
6151  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6152  {
6153  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6154  }
6155  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6156  {
6157  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6158  }
6159  Utilities->CallLogPop(1101);
6160 }
6161 
6162 // ---------------------------------------------------------------------------
6163 
6164 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6165 {
6166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6167  TrackElement.PlotVariableTrackElement(7, Disp);
6168  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6169  {
6170  THVPair PosPair;
6171  PosPair.first = TrackElement.HLoc;
6172  PosPair.second = TrackElement.VLoc;
6173  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6174  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6175  {
6176  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6177  }
6178  }
6179  Utilities->CallLogPop(2403);
6180 }
6181 
6182 // ---------------------------------------------------------------------------
6183 
6184 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6185 {
6186  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6187  if(TrackElement.TrackType != Points)
6188  {
6189  throw Exception("Error, Wrong track type in PlotPoints");
6190  }
6191  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6192  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6193  bool FoundFlag = false;
6194  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6195  if(IMPair.first > 0) //can only have one entry in IMPair for points
6196  {
6197  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6198  if(ITE.SpeedTag == 131)
6199  {
6200  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6201  }
6202  }
6203  TrackElement.PlotVariableTrackElement(4, Disp);
6204  if(BothFillets)
6205  {
6206  if(TrackElement.SpeedTag < 28)
6207  {
6208  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6209  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6210  }
6211  else if(TrackElement.SpeedTag < 132)
6212  {
6213  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6214  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6215  }
6216  else
6217  {
6218  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6219  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6220  }
6221  }
6222  else if(!TrackElement.Failed) //not failed
6223  {
6224  if(TrackElement.SpeedTag < 28)
6225  {
6226  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6227  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6228  }
6229  else if(TrackElement.SpeedTag < 132)
6230  {
6231  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6232  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6233  }
6234  else
6235  {
6236  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6237  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6238  }
6239  }
6240  else //failed in fixed position
6241  {
6242  if(TrackElement.SpeedTag < 28)
6243  {
6244  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6245  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6246  }
6247  else if(TrackElement.SpeedTag < 132)
6248  {
6249  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6250  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6251  }
6252  else
6253  {
6254  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6255  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6256  }
6257  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6258  }
6259 // replot platform if required
6260  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6261  bool BlueLoc = false;
6262  if(FoundFlag)
6263  {
6264  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6265  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these or the track is obscured - added at v2.18.0
6266  {
6267  BlueLoc = true;
6268  }
6269  }
6270  if(FoundFlag && !BlueLoc)
6271  {
6272  // only one platform possible at points so only need to plot IMPair.first
6273  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6274  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6275  }
6276  Utilities->CallLogPop(519);
6277 }
6278 
6279 // ---------------------------------------------------------------------------
6280 
6281 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6282 {
6283 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6284  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6285  bool FoundFlag = false;
6286  if(TrackElement.TrackType != SignalPost)
6287  {
6288  throw Exception("Error, Wrong track type in PlotSignal");
6289  }
6290  if(!TrackElement.Failed) //added at v2.13.0
6291  {
6292  for(int x = 0; x < 40; x++)
6293  {
6294  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6295  {
6296  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6297  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6298  // in case existing signal is a double yellow
6299  // plot platforms if present
6300  // Graphics::TBitmap* SignalPlatformGraphic;
6301  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6302  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6303  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6304  // to not be plotted with the above function.
6305 
6306  //replot the blue square to cover the blank area - added at v2.18.0
6307  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(36, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6308  if(FoundFlag) //changed at v2.23.2, was if(IMPair.first > 0) but this excluded vector position 0 which it would be if it was the first inactive element
6309  {
6310  TTrackElement ITE = InactiveTrackElementAt(1414, IMPair.first); //can only have one entry in IMPair for a blue square (second entry is only for second platform)
6311  if(ITE.SpeedTag == 131)
6312  {
6313  ITE.PlotVariableTrackElement(9, Disp); //plot the blue square again to cover the blank area
6314  }
6315  }
6316 
6317  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6318  // now plot signal (double yellow overwrites most of signal platform if present)
6319  // additions at version 0.6 for other aspects & ground sigs
6320  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6321  {
6322  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6323  }
6324  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6325  {
6326  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6327  }
6328  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6329  {
6330  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6331  }
6332  else // 4 aspect
6333  {
6334  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6335  }
6336  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6337  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6338  {
6339  if(TrackElement.SpeedTag == 68)
6340  {
6341  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6342  }
6343  if(TrackElement.SpeedTag == 69)
6344  {
6345  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6346  }
6347  if(TrackElement.SpeedTag == 70)
6348  {
6349  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6350  }
6351  if(TrackElement.SpeedTag == 71)
6352  {
6353  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6354  }
6355  if(TrackElement.SpeedTag == 72)
6356  {
6357  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6358  }
6359  if(TrackElement.SpeedTag == 73)
6360  {
6361  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6362  }
6363  if(TrackElement.SpeedTag == 74)
6364  {
6365  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6366  }
6367  if(TrackElement.SpeedTag == 75)
6368  {
6369  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6370  }
6371  }
6372  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6373  // ground signal calling on, need to use normal proceed aspect
6374  {
6375  for(int x = 0; x < 40; x++)
6376  {
6377  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6378  {
6379  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6380  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6381  // plot special signal platform if present
6382  Graphics::TBitmap* SignalPlatformGraphic;
6383  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(37, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6384  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6385  {
6386  TTrackElement ITE = InactiveTrackElementAt(1415, IMPair.first);
6387  if(ITE.SpeedTag == 131)
6388  {
6389  ITE.PlotVariableTrackElement(10, Disp); //plot the blue square again to cover the blank area
6390  }
6391  }
6392  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6393  // now plot signal
6394  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6395  }
6396  }
6397  }
6398  break;
6399  }
6400  }
6401  }
6402  else //failed added at v2.13.0
6403  {
6404  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6405  {
6406  for(int x = 0; x < 8; x++)
6407  {
6408  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6409  {
6410  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6411  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6412  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(38, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6413  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6414  {
6415  TTrackElement ITE = InactiveTrackElementAt(1416, IMPair.first);
6416  if(ITE.SpeedTag == 131)
6417  {
6418  ITE.PlotVariableTrackElement(11, Disp); //plot the blue square again to cover the blank area
6419  }
6420  }
6421  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6422  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6423  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6424  break;
6425  }
6426  }
6427  }
6428  else
6429  {
6430  for(int x = 0; x < 8; x++)
6431  {
6432  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6433  {
6434  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6435  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6436  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(39, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6437  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6438  {
6439  TTrackElement ITE = InactiveTrackElementAt(1417, IMPair.first);
6440  if(ITE.SpeedTag == 131)
6441  {
6442  ITE.PlotVariableTrackElement(12, Disp); //plot the blue square again to cover the blank area
6443  }
6444  }
6445  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6446  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6447  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6448  break;
6449  }
6450  }
6451  }
6452  }
6453  Utilities->CallLogPop(520);
6454 }
6455 
6456 // ---------------------------------------------------------------------------
6457 
6458 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6459 {
6460  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6461  bool FoundFlag;
6462  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6463 
6464  if(!FoundFlag)
6465  {
6466  Utilities->CallLogPop(2112);
6467  return;
6468  }
6469  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6470  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6471 
6472  // don't want 'else if' for the below as may need to plot 2 platforms
6473  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6474  {
6475  if(IAElement1.LocationName == "") // '2' will be same
6476  {
6477  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6478  }
6479  else
6480  {
6481  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6482  }
6483  }
6484  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6485  {
6486  if(IAElement1.LocationName == "") // '2' will be same
6487  {
6488  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6489  }
6490  else
6491  {
6492  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6493  }
6494  }
6495  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6496  {
6497  if(IAElement1.LocationName == "") // '2' will be same
6498  {
6499  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6500  }
6501  else
6502  {
6503  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6504  }
6505  }
6506  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6507  {
6508  if(IAElement1.LocationName == "") // '2' will be same
6509  {
6510  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6511  }
6512  else
6513  {
6514  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6515  }
6516  }
6517  Utilities->CallLogPop(2113);
6518 }
6519 
6520 // ---------------------------------------------------------------------------
6521 
6522 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6523 {
6524 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6525  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6526  AnsiString(VLoc));
6527 // find topmost LC, opening them all (to trains) in turn
6528  int UpStep = 0;
6529 
6530  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6531  {
6532  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6533  UpStep--;
6534  }
6535 // now find bottommost LC, opening them all (to trains) in turn
6536  int DownStep = 1;
6537 
6538  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6539  {
6540  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6541  DownStep++;
6542  }
6543 // find leftmost LC, opening them all (to trains) in turn
6544  int LeftStep = 0;
6545 
6546  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6547  {
6548  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6549  LeftStep--;
6550  }
6551 // now find rightmost LC, opening them all (to trains) in turn
6552  int RightStep = 1;
6553 
6554  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6555  {
6556  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6557  RightStep++;
6558  }
6559  Utilities->CallLogPop(1915);
6560 }
6561 
6562 // ---------------------------------------------------------------------------
6563 
6564 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6565 {
6566  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6567 // work upwards setting all to manual
6568  int UpStep = -1;
6569 
6570  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6571  {
6572  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6573  UpStep--;
6574  }
6575 // work downwards setting all to manual
6576  int DownStep = 1;
6577 
6578  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6579  {
6580  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6581  DownStep++;
6582  }
6583 // work leftwards setting all to manual
6584  int LeftStep = -1;
6585 
6586  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6587  {
6588  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6589  LeftStep--;
6590  }
6591 // work rightwards setting all to manual
6592  int RightStep = 1;
6593 
6594  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6595  {
6596  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6597  RightStep++;
6598  }
6599  Utilities->CallLogPop(2242);
6600 }
6601 
6602 // ---------------------------------------------------------------------------
6603 
6604 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6605 {
6606  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6608  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6609  {
6610  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6611  {
6612  BarriersDownVector.at(x).TypeOfRoute = 2;
6613  break;
6614  }
6615  }
6616  Utilities->CallLogPop(2243);
6617 }
6618 
6619 // ---------------------------------------------------------------------------
6620 
6621 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6622 {
6623  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6624 // work upwards
6625  int UpStep = 0; //start with this location
6626 
6627  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6628  {
6629  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6630  {
6631  Utilities->CallLogPop(2244);
6632  return(true);
6633  }
6634  UpStep--;
6635  }
6636 // work downwards
6637  int DownStep = 1;
6638 
6639  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6640  {
6641  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6642  {
6643  Utilities->CallLogPop(2245);
6644  return(true);
6645  }
6646  DownStep++;
6647  }
6648 // work leftwards
6649  int LeftStep = -1;
6650 
6651  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6652  {
6653  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6654  {
6655  Utilities->CallLogPop(2246);
6656  return(true);
6657  }
6658  LeftStep--;
6659  }
6660 // work rightwards
6661  int RightStep = 1;
6662 
6663  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6664  {
6665  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6666  {
6667  Utilities->CallLogPop(2247);
6668  return(true);
6669  }
6670  RightStep++;
6671  }
6672  Utilities->CallLogPop(2248);
6673  return(false);
6674 }
6675 
6676 // ---------------------------------------------------------------------------
6677 
6678 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6679 {
6680  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6681  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6682  {
6683  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6684  {
6685  BDVectorPos = x;
6686  Utilities->CallLogPop(2249);
6687  return(true);
6688  }
6689  }
6690  BDVectorPos = -1;
6691  Utilities->CallLogPop(2250);
6692  return(false);
6693 }
6694 
6695 // ---------------------------------------------------------------------------
6696 
6697 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6698 // open to trains
6699 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6700 {
6701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6702  AnsiString(VLoc));
6703  if(!IsLCAtHV(4, HLoc, VLoc))
6704  {
6705  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6706  }
6707  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6708  {
6709  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6710  }
6711 // check for adjacent LCs & if so open (to trains)
6712  if(BaseElementSpeedTag == 1) // hor track element
6713  {
6714  // find topmost LC, opening them all (to trains) in turn
6715  int UpStep = 0;
6716  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6717  {
6718  UpStep--;
6719  }
6720  UpStep++;
6721  // now find bottommost LC, opening them all (to trains) in turn
6722  int DownStep = 1;
6723  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6724  {
6725  DownStep++;
6726  }
6727  DownStep--;
6728  // now plot graphics, UpStep is smallest & DownStep largest
6729  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6730  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6731  Graphics::TBitmap *RouteGraphic;
6732  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6733  if(TypeOfRoute == 1)
6734  {
6735  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6736  }
6737  else if(TypeOfRoute == 0)
6738  {
6739  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6740  }
6741  else //manual - no route
6742  {
6743  RouteGraphic = BaseGraphic;
6744  }
6745 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6746 // LinkSigRouteGraphicsPtr[1] ver }
6747 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6748 // LinkNonSigRouteGraphicsPtr[1] ver }
6749 
6750  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6751  {
6752  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6753  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6754  if(!Manual)
6755  {
6756  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6757  }
6758  else
6759  {
6760  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6761  }
6762  }
6763  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6764  {
6765  if(UpStep == 0)
6766  {
6767  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6768  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6769  if(!Manual)
6770  {
6771  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6772  }
6773  else
6774  {
6775  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6776  }
6777  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6778  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6779  if(!Manual)
6780  {
6781  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6782  }
6783  else
6784  {
6785  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6786  }
6787  }
6788  else
6789  {
6790  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6791  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6792  if(!Manual)
6793  {
6794  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6795  }
6796  else
6797  {
6798  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6799  }
6800  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6801  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6802  if(!Manual)
6803  {
6804  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6805  }
6806  else
6807  {
6808  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6809  }
6810  }
6811  }
6812  else // at least one plain graphic
6813  {
6814  if(UpStep == 0)
6815  {
6816  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6817  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6818  if(!Manual)
6819  {
6820  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6821  }
6822  else
6823  {
6824  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6825  }
6826  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6827  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6828  if(!Manual)
6829  {
6830  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6831  }
6832  else
6833  {
6834  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6835  }
6836  }
6837  else if(DownStep == 0)
6838  {
6839  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6840  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6841  if(!Manual)
6842  {
6843  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6844  }
6845  else
6846  {
6847  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6848  }
6849  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6850  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6851  if(!Manual)
6852  {
6853  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6854  }
6855  else
6856  {
6857  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6858  }
6859  }
6860  else
6861  {
6862  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6863  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6864  if(!Manual)
6865  {
6866  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6867  }
6868  else
6869  {
6870  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6871  }
6872  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6873  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6874  if(!Manual)
6875  {
6876  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6877  }
6878  else
6879  {
6880  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6881  }
6882  }
6883  for(int x = (UpStep + 1); x < DownStep; x++)
6884  {
6885  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6886  if(x == 0)
6887  {
6888  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6889  }
6890  else
6891  {
6892  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6893  }
6894  if(!Manual)
6895  {
6896  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6897  }
6898  else
6899  {
6900  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6901  }
6902  }
6903  }
6904  Disp->Update();
6905  Utilities->CallLogPop(1958);
6906  return;
6907  }
6908 
6909  else // ver track element
6910  {
6911  // find leftmost LC, opening them all (to trains) in turn
6912  int LStep = 0;
6913  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6914  {
6915  LStep--;
6916  }
6917  LStep++;
6918  // now find rightmost LC, opening them all (to trains) in turn
6919  int RStep = 1;
6920  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6921  {
6922  RStep++;
6923  }
6924  RStep--;
6925  // now plot graphics, LStep is smallest & RStep largest
6926  Graphics::TBitmap *RouteGraphic;
6927  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6928  if(TypeOfRoute == 1)
6929  {
6930  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6931  }
6932  else if(TypeOfRoute == 0)
6933  {
6934  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6935  }
6936  else //manual
6937  {
6938  RouteGraphic = BaseGraphic;
6939  }
6940 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6941 // LinkSigRouteGraphicsPtr[1] ver }
6942 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6943 // LinkNonSigRouteGraphicsPtr[1] ver }
6944  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6945  {
6946  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6947  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6948  if(!Manual)
6949  {
6950  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6951  }
6952  else
6953  {
6954  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6955  }
6956  }
6957  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6958  {
6959  if(LStep == 0)
6960  {
6961  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6962  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6963  if(!Manual)
6964  {
6965  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6966  }
6967  else
6968  {
6969  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6970  }
6971  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6972  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6973  if(!Manual)
6974  {
6975  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6976  }
6977  else
6978  {
6979  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6980  }
6981  }
6982  else
6983  {
6984  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6985  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6986  if(!Manual)
6987  {
6988  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6989  }
6990  else
6991  {
6992  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6993  }
6994  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6995  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6996  if(!Manual)
6997  {
6998  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6999  }
7000  else
7001  {
7002  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7003  }
7004  }
7005  }
7006  else // at least one plain graphic
7007  {
7008  if(LStep == 0)
7009  {
7010  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7011  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
7012  if(!Manual)
7013  {
7014  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7015  }
7016  else
7017  {
7018  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7019  }
7020  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7021  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7022  if(!Manual)
7023  {
7024  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7025  }
7026  else
7027  {
7028  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7029  }
7030  }
7031  else if(RStep == 0)
7032  {
7033  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7034  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7035  if(!Manual)
7036  {
7037  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7038  }
7039  else
7040  {
7041  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7042  }
7043  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7044  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7045  if(!Manual)
7046  {
7047  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7048  }
7049  else
7050  {
7051  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7052  }
7053  }
7054  else
7055  {
7056  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7057  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7058  if(!Manual)
7059  {
7060  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7061  }
7062  else
7063  {
7064  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7065  }
7066  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7067  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7068  if(!Manual)
7069  {
7070  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7071  }
7072  else
7073  {
7074  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7075  }
7076  }
7077  for(int x = (LStep + 1); x < RStep; x++)
7078  {
7079  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7080  if(x == 0)
7081  {
7082  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7083  }
7084  else
7085  {
7086  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7087  }
7088  if(!Manual)
7089  {
7090  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7091  }
7092  else
7093  {
7094  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7095  }
7096  }
7097  }
7098  Disp->Update();
7099  Utilities->CallLogPop(1896);
7100  return;
7101  }
7102 }
7103 
7104 // ---------------------------------------------------------------------------
7105 
7106 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7107 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7108 {
7109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7110  AnsiString(HLoc) + "," + AnsiString(VLoc));
7111  if(!IsLCAtHV(29, HLoc, VLoc))
7112  {
7113  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7114  }
7115  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7116  {
7117  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7118  }
7119 // check for adjacent LCs & if so open (to trains)
7120  if(BaseElementSpeedTag == 1) // hor track element
7121  {
7122  // find topmost LC, opening them all (to trains) in turn
7123  int UpStep = 0;
7124  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7125  {
7126  UpStep--;
7127  }
7128  UpStep++;
7129  // now find bottommost LC, opening them all (to trains) in turn
7130  int DownStep = 1;
7131  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7132  {
7133  DownStep++;
7134  }
7135  DownStep--;
7136  // now plot graphics, UpStep is smallest & DownStep largest
7137  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7138  {
7139  if(!Manual)
7140  {
7141  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7142  }
7143  else
7144  {
7145  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7146  }
7147  }
7148  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7149  {
7150  if(!Manual)
7151  {
7152  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7153  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7154  }
7155  else
7156  {
7157  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7158  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7159  }
7160  }
7161  else // at least one plain graphic
7162  {
7163  if(!Manual)
7164  {
7165  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7166  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7167  for(int x = (UpStep + 1); x < DownStep; x++)
7168  {
7169  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7170  }
7171  }
7172  else
7173  {
7174  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7175  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7176  for(int x = (UpStep + 1); x < DownStep; x++)
7177  {
7178  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7179  }
7180  }
7181  }
7182  // set markers
7183  for(int x = UpStep; x <= DownStep; x++)
7184  {
7185  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7186  }
7187  Display->Update();
7188  Utilities->CallLogPop(1944);
7189  return;
7190  }
7191 
7192  else // ver track element
7193  {
7194  // find leftmost LC, opening them all (to trains) in turn
7195  int LStep = 0;
7196  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7197  {
7198  LStep--;
7199  }
7200  LStep++;
7201  // now find rightmost LC, opening them all (to trains) in turn
7202  int RStep = 1;
7203  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7204  {
7205  RStep++;
7206  }
7207  RStep--;
7208  // now plot graphics, LStep is smallest & RStep largest
7209  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7210  {
7211  if(!Manual)
7212  {
7213  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7214  }
7215  else
7216  {
7217  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7218  }
7219  }
7220  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7221  {
7222  if(!Manual)
7223  {
7224  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7225  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7226  }
7227  else
7228  {
7229  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7230  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7231  }
7232  }
7233  else // at least one plain graphic
7234  {
7235  if(!Manual)
7236  {
7237  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7238  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7239  for(int x = (LStep + 1); x < RStep; x++)
7240  {
7241  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7242  }
7243  }
7244  else
7245  {
7246  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7247  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7248  for(int x = (LStep + 1); x < RStep; x++)
7249  {
7250  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7251  }
7252  }
7253  }
7254  // set markers
7255  for(int x = LStep; x <= RStep; x++)
7256  {
7257  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7258  }
7259  Disp->Update();
7260  Utilities->CallLogPop(1945);
7261  return;
7262  }
7263 }
7264 
7265 // ---------------------------------------------------------------------------
7266 
7267 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7268 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7269 {
7270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7271  AnsiString(VLoc));
7272  if(!IsLCAtHV(9, HLoc, VLoc))
7273  {
7274  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7275  }
7276  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7277  {
7278  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7279  }
7280 // check for adjacent LCs & if so close (to trains)
7281  if(BaseElementSpeedTag == 1) // hor track element
7282  {
7283  // find topmost LC, closing them all (to trains) in turn
7284  int UpStep = 0;
7285  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7286  {
7287  UpStep--;
7288  }
7289  UpStep++;
7290  // now find bottommost LC, opening them all (to trains) in turn
7291  int DownStep = 1;
7292  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7293  {
7294  DownStep++;
7295  }
7296  DownStep--;
7297  // now plot graphics, UpStep is smallest & DownStep largest
7298  for(int x = UpStep; x < (DownStep + 1); x++)
7299  {
7300  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7301  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7302  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7303  }
7304  Disp->Update();
7305  Utilities->CallLogPop(1959);
7306  return;
7307  }
7308 
7309  else // ver track element
7310  {
7311  // find leftmost LC, closing them all (to trains) in turn
7312  int LStep = 0;
7313  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7314  {
7315  LStep--;
7316  }
7317  LStep++;
7318  // now find rightmost LC, opening them all (to trains) in turn
7319  int RStep = 1;
7320  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7321  {
7322  RStep++;
7323  }
7324  RStep--;
7325  // now plot graphics, LStep is smallest & RStep largest
7326  for(int x = LStep; x < (RStep + 1); x++)
7327  {
7328  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7329  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7330  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7331  }
7332  Disp->Update();
7333  Utilities->CallLogPop(1960);
7334  return;
7335  }
7336 }
7337 
7338 // ---------------------------------------------------------------------------
7339 
7340 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7341 // closed to trains
7342 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7343 {
7344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7345  AnsiString(HLoc) + "," + AnsiString(VLoc));
7346  if(!IsLCAtHV(34, HLoc, VLoc))
7347  {
7348  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7349  }
7350  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7351  {
7352  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7353  }
7354  TTrackElement TE;
7355 
7356 // check for adjacent LCs & if so close (to trains)
7357  if(BaseElementSpeedTag == 1) // hor track element
7358  {
7359  // find topmost LC, closing them all (to trains) in turn
7360  int UpStep = 0;
7361  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7362  {
7363  UpStep--;
7364  }
7365  UpStep++;
7366  // now find bottommost LC, opening them all (to trains) in turn
7367  int DownStep = 1;
7368  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7369  {
7370  DownStep++;
7371  }
7372  DownStep--;
7373  // now plot graphics, UpStep is smallest & DownStep largest
7374  for(int x = UpStep; x <= DownStep; x++)
7375  {
7376  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7377  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7378  }
7379  Display->Update();
7380  Utilities->CallLogPop(1946);
7381  return;
7382  }
7383 
7384  else // ver track element
7385  {
7386  // find leftmost LC, closing them all (to trains) in turn
7387  int LStep = 0;
7388  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7389  {
7390  LStep--;
7391  }
7392  LStep++;
7393  // now find rightmost LC, opening them all (to trains) in turn
7394  int RStep = 1;
7395  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7396  {
7397  RStep++;
7398  }
7399  RStep--;
7400  // now plot graphics, LStep is smallest & RStep largest
7401  for(int x = LStep; x <= RStep; x++)
7402  {
7403  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7404  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7405  }
7406  Display->Update();
7407  Utilities->CallLogPop(1947);
7408  return;
7409  }
7410 }
7411 
7412 // ---------------------------------------------------------------------------
7413 
7414 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7415 {
7416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7417  Graphics::TBitmap *RouteGraphic;
7418  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7419 
7420  if(BaseElementSpeedTag == 1)
7421  {
7422  if(TypeOfRoute == 1)
7423  {
7424  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7425  }
7426  else if(TypeOfRoute == 0)
7427  {
7428  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7429  }
7430  else //manual
7431  {
7432  RouteGraphic = BaseGraphic;
7433  }
7434  if(State == Raising)
7435  {
7436  RouteGraphic = BaseGraphic;
7437  }
7438  }
7439  else
7440  {
7441  BaseGraphic = RailGraphics->gl2;
7442  if(TypeOfRoute == 1)
7443  {
7444  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7445  }
7446  else if(TypeOfRoute == 0)
7447  {
7448  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7449  }
7450  else
7451  {
7452  RouteGraphic = BaseGraphic; //manual
7453  }
7454  if(State == Raising)
7455  {
7456  RouteGraphic = BaseGraphic;
7457  }
7458  }
7459  int UpStep = 0;
7460 
7461  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7462  {
7463  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7464  if(UpStep == 0)
7465  {
7466  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7467  }
7468  else
7469  {
7470  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7471  }
7472  UpStep--;
7473  }
7474 // now find bottommost LC, opening them all (to trains) in turn
7475  int DownStep = 1;
7476 
7477  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7478  {
7479  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7480  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7481  DownStep++;
7482  }
7483  int LeftStep = 0;
7484 
7485  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7486  {
7487  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7488  if(LeftStep == 0)
7489  {
7490  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7491  }
7492  else
7493  {
7494  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7495  }
7496  LeftStep--;
7497  }
7498 // now find rightmost LC, opening them all (to trains) in turn
7499  int RightStep = 1;
7500 
7501  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7502  {
7503  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7504  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7505  RightStep++;
7506  }
7507  Disp->Update();
7508  Utilities->CallLogPop(1914);
7509 }
7510 
7511 // ---------------------------------------------------------------------------
7512 
7513 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7514 {
7515 // return false for no LC there, flashing or a closed (to trains) LC
7516  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7517  bool FoundFlag;
7518  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7519 
7520  if(!FoundFlag)
7521  {
7522  Utilities->CallLogPop(1898);
7523  return(false);
7524  }
7525  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7526  {
7527  Utilities->CallLogPop(1899);
7528  return(false);
7529  }
7530  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7531  {
7532  Utilities->CallLogPop(1900);
7533  return(true);
7534  }
7535  Utilities->CallLogPop(1901);
7536  return(false);
7537 }
7538 
7539 // ---------------------------------------------------------------------------
7540 
7541 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7542 {
7543 // return false for no LC there, flashing LC or open (to trains) LC
7544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7545  bool FoundFlag;
7546  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7547 
7548  if(!FoundFlag)
7549  {
7550  Utilities->CallLogPop(1922);
7551  return(false);
7552  }
7553  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7554  {
7555  Utilities->CallLogPop(1923);
7556  return(false);
7557  }
7558  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7559  {
7560  Utilities->CallLogPop(1924);
7561  return(true);
7562  }
7563  Utilities->CallLogPop(1925);
7564  return(false);
7565 }
7566 
7567 // ---------------------------------------------------------------------------
7568 
7569 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7570 {
7571 // return true for barrier in process of moving
7572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7573  bool FoundFlag;
7574  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7575 
7576  if(!FoundFlag)
7577  {
7578  Utilities->CallLogPop(1918);
7579  return(false);
7580  }
7581  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7582  {
7583  Utilities->CallLogPop(1919);
7584  return(false);
7585  }
7586  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7587  {
7588  Utilities->CallLogPop(1920);
7589  return(true);
7590  }
7591  Utilities->CallLogPop(1921);
7592  return(false);
7593 }
7594 
7595 // ---------------------------------------------------------------------------
7596 
7597 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7598 {
7599 // return true for an LC at H&V
7600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7601  bool FoundFlag;
7602  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7603 
7604  if(!FoundFlag)
7605  {
7606  Utilities->CallLogPop(1902);
7607  return(false);
7608  }
7609  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7610  {
7611  Utilities->CallLogPop(1903);
7612  return(false);
7613  }
7614  Utilities->CallLogPop(1904);
7615  return(true);
7616 }
7617 
7618 // ---------------------------------------------------------------------------
7619 
7620 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7621 {
7622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7623  AnsiString(Attr));
7624  bool FoundFlag;
7625  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7626 
7627  if(!FoundFlag)
7628  {
7629  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7630  }
7631  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7632  {
7633  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7634  }
7635  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7636  Utilities->CallLogPop(1905);
7637  return;
7638 }
7639 
7640 // ---------------------------------------------------------------------------
7641 
7643 {
7644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7645  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7646  {
7647  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7648  if(InactiveTrackElement.TrackType == LevelCrossing)
7649  {
7650  InactiveTrackElementAt(141, x).Attribute = 0;
7651  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7652  }
7653  }
7654  Utilities->CallLogPop(1913);
7655  return;
7656 }
7657 
7658 // ---------------------------------------------------------------------------
7659 
7660 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7661 {
7662 // return true if there is either a route set or being set on any element or a train on any element
7663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7664  "," + AnsiString(VLoc));
7665 
7666  THVPair TrackMapKeyPair;
7667  TTrack::TTrackMapIterator TrackMapPtr;
7668  int DummyRouteNumber;
7669 
7670  TrainPresent = false;
7671 // find topmost LC, checking each for routes & trains
7672  int UpStep = 0;
7673 
7674  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7675  {
7676  TrackMapKeyPair.first = HLoc;
7677  TrackMapKeyPair.second = VLoc + UpStep;
7678  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7679  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7680  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7681  {
7682  Utilities->CallLogPop(1932);
7683  return(true);
7684  }
7685  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7686  {
7687  TrainPresent = true;
7688  Utilities->CallLogPop(1933);
7689  return(true);
7690  }
7691  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7692  {
7693  Utilities->CallLogPop(2274);
7694  return(true);
7695  }
7696  UpStep--;
7697  }
7698 // now find bottommost LC, opening them all (to trains) in turn
7699  int DownStep = 1;
7700 
7701  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7702  {
7703  TrackMapKeyPair.first = HLoc;
7704  TrackMapKeyPair.second = VLoc + DownStep;
7705  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7706  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7707  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7708  {
7709  Utilities->CallLogPop(1934);
7710  return(true);
7711  }
7712  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7713  {
7714  TrainPresent = true;
7715  Utilities->CallLogPop(1935);
7716  return(true);
7717  }
7718  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7719  {
7720  Utilities->CallLogPop(2275);
7721  return(true);
7722  }
7723  DownStep++;
7724  }
7725 // find leftmost LC
7726  int LeftStep = 0;
7727 
7728  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7729  {
7730  TrackMapKeyPair.first = HLoc + LeftStep;
7731  TrackMapKeyPair.second = VLoc;
7732  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7733  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7734  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7735  {
7736  Utilities->CallLogPop(1936);
7737  return(true);
7738  }
7739  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7740  {
7741  TrainPresent = true;
7742  Utilities->CallLogPop(1937);
7743  return(true);
7744  }
7745  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7746  {
7747  Utilities->CallLogPop(2276);
7748  return(true);
7749  }
7750  LeftStep--;
7751  }
7752 // now find rightmost LC, opening them all (to trains) in turn
7753  int RightStep = 1;
7754 
7755  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7756  {
7757  TrackMapKeyPair.first = HLoc + RightStep;
7758  TrackMapKeyPair.second = VLoc;
7759  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7760  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7761  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7762  {
7763  Utilities->CallLogPop(1938);
7764  return(true);
7765  }
7766  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7767  {
7768  TrainPresent = true;
7769  Utilities->CallLogPop(1939);
7770  return(true);
7771  }
7772  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7773  {
7774  Utilities->CallLogPop(2277);
7775  return(true);
7776  }
7777  RightStep++;
7778  }
7779  Utilities->CallLogPop(1940);
7780  return(false);
7781 }
7782 
7783 // ---------------------------------------------------------------------------
7784 
7785 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7786 {
7787  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7788  for(unsigned int x = 0; x < SearchVector.size(); x++)
7789  {
7790  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7791  {
7792  Utilities->CallLogPop(2278);
7793  return(true);
7794  }
7795  }
7796  Utilities->CallLogPop(2279);
7797  return(false);
7798 }
7799 
7800 // ---------------------------------------------------------------------------
7801 
7802 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7803 {
7804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7805  AnsiString(HLoc) + "," + AnsiString(VLoc));
7806  if(!IsLCAtHV(60, HLoc, VLoc))
7807  {
7808  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7809  }
7810 
7811 // check for adjacent LCs
7812  // find topmost LC
7813  int UpStep = 0;
7814  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7815  {
7816  UpStep--;
7817  }
7818  UpStep++;
7819  // now find bottommost LC, opening them all (to trains) in turn
7820  int DownStep = 1;
7821  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7822  {
7823  DownStep++;
7824  }
7825  DownStep--;
7826  // now plot graphics, UpStep is smallest & DownStep largest
7827  for(int x = UpStep; x <= DownStep; x++)
7828  {
7829  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7830  }
7831 
7832  // find leftmost LC, closing them all (to trains) in turn
7833  int LStep = 0;
7834  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7835  {
7836  LStep--;
7837  }
7838  LStep++;
7839  // now find rightmost LC, opening them all (to trains) in turn
7840  int RStep = 1;
7841  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7842  {
7843  RStep++;
7844  }
7845  RStep--;
7846  // now plot graphics, LStep is smallest & RStep largest
7847  for(int x = LStep; x <= RStep; x++)
7848  {
7849  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7850  }
7851  Display->Update();
7852  Utilities->CallLogPop(2315);
7853  return;
7854 }
7855 
7856 // ---------------------------------------------------------------------------
7857 
7858 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7859 {
7860  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7861  if(TrackElement.TrackType != Points)
7862  {
7863  throw Exception("Error, Wrong track type in GetFilletGraphic");
7864  }
7865  if(TrackElement.SpeedTag < 28)
7866  {
7867  Utilities->CallLogPop(521);
7868  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7869  }
7870  else if(TrackElement.SpeedTag < 132)
7871  {
7872  Utilities->CallLogPop(522);
7873 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7874  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7875  }
7876  else
7877  {
7878  Utilities->CallLogPop(1537);
7879  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7880  }
7881 }
7882 
7883 // ---------------------------------------------------------------------------
7884 
7886 {
7887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7888  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7889  {
7890  TrackElementAt(1351, x).TrainIDOnElement = -1;
7893  }
7894  Utilities->CallLogPop(1342);
7895 }
7896 
7897 // ---------------------------------------------------------------------------
7898 
7899 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7900 /*
7901  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7902 */
7903 {
7904  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7905  AnsiString(ScreenPosV));
7906  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7907  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7908 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7909  Utilities->CallLogPop(535);
7910 }
7911 
7912 // ---------------------------------------------------------------------------
7913 
7914 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7915 /*
7916  Converts the screen position to the true (without offsets) position
7917 */
7918 {
7919  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7920  AnsiString(ScreenPosV));
7921  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7922  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7923  Utilities->CallLogPop(536);
7924 }
7925 
7926 // ---------------------------------------------------------------------------
7927 
7928 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7929 {
7930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7931  AnsiString(VPosTrue));
7932  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7933  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7934  Utilities->CallLogPop(537);
7935 }
7936 
7937 // ---------------------------------------------------------------------------
7938 
7939 void TTrack::CheckMapAndTrack(int Caller) // test
7940 {
7941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7942  int Zeroes = 0;
7943  bool FoundFlag;
7944 
7945  for(unsigned int a = 0; a < TrackVector.size(); a++)
7946  {
7947  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7948  if(CheckElement.SpeedTag == 0)
7949  {
7950  Zeroes++; // zeroed elements not saved in map
7951  }
7952  else
7953  {
7954  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7955  if(!FoundFlag)
7956  {
7957  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7958  " in TrackMap, Caller=" + (AnsiString)Caller);
7959  }
7960  if(MapVecPos != (int)a)
7961  {
7962  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7963  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7964  (AnsiString)Caller);
7965  }
7966  }
7967  }
7968  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7969  {
7970  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7971  " Caller=" + (AnsiString)Caller);
7972  }
7973  Utilities->CallLogPop(538);
7974  return;
7975 }
7976 
7977 // ---------------------------------------------------------------------------
7978 
7979 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7980 {
7981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7982  bool FoundFlag;
7983  TIMPair InactivePair;
7984 
7985  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7986  {
7987  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7988  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7989  if(!FoundFlag)
7990  {
7991  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7992  " in InactiveMap, Caller=" + (AnsiString)Caller);
7993  }
7994  if((InactivePair.first != a) && (InactivePair.second != a))
7995  {
7996  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7997  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7998  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7999  }
8000  }
8001  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
8002  {
8003  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
8004  " Caller=" + (AnsiString)Caller);
8005  }
8006  Utilities->CallLogPop(539);
8007 }
8008 
8009 // ---------------------------------------------------------------------------
8010 
8011 void TTrack::CheckGapMap(int Caller) // test
8012 {
8013  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
8014  int Position1, Position2;
8015  TTrackElement TrackElement1, TrackElement2;
8016  TGapMapIterator GapMapPtr;
8017 
8018  if(!GapMap.empty())
8019  {
8020  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
8021  {
8022  int HLoc1 = GapMapPtr->first.first;
8023  int VLoc1 = GapMapPtr->first.second;
8024  int HLoc2 = GapMapPtr->second.first;
8025  int VLoc2 = GapMapPtr->second.second;
8026  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
8027  {
8028  throw Exception("Failed to find H & V for gap1, GapMap in error");
8029  }
8030  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
8031  {
8032  throw Exception("Failed to find H & V for gap2, GapMap in error");
8033  }
8034  if(TrackElementAt(17, Position1).TrackType != GapJump)
8035  {
8036  throw Exception("Element at Pos1 not a gap, GapMap in error");
8037  }
8038  if(TrackElementAt(18, Position2).TrackType != GapJump)
8039  {
8040  throw Exception("Element at Pos2 not a gap, GapMap in error");
8041  }
8042  }
8043  }
8044  unsigned int GapCount = 0;
8045 
8046  for(unsigned int a = 0; a < TrackVector.size(); a++)
8047  {
8048  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
8049  if(CheckElement.TrackType == GapJump)
8050  {
8051  GapCount++;
8052  }
8053  }
8054  if((GapMap.size() * 2) != GapCount)
8055  {
8056  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
8057  (AnsiString)Caller);
8058  }
8059  Utilities->CallLogPop(540);
8060 }
8061 
8062 // ---------------------------------------------------------------------------
8063 
8064 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
8065 {
8066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
8067  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
8068  {
8069  if(TrackFinished)
8070  {
8071  throw Exception("Error - TrackFinished with erase element still present");
8072  }
8073  Utilities->CallLogPop(541);
8074  return; // erased element, can't set ID
8075  }
8076  AnsiString IDString;
8077 
8078  if(TrackElement.HLoc < 0)
8079  {
8080  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8081  }
8082  else
8083  {
8084  IDString = AnsiString(TrackElement.HLoc) + "-";
8085  }
8086  if(TrackElement.VLoc < 0)
8087  {
8088  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8089  }
8090  else
8091  {
8092  IDString += AnsiString(TrackElement.VLoc);
8093  }
8094  TrackElement.ElementID = IDString;
8095  Utilities->CallLogPop(542);
8096 }
8097 
8098 // ---------------------------------------------------------------------------
8099 
8100 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8101 {
8102 // e.g. "8-13", "00008-13", "N43-N127", etc
8103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8104  int DelimPos;
8105 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8106  {
8107  for(int x = 1; x < String.Length() + 1; x++)
8108  {
8109  if(String.IsDelimiter("-", x))
8110  {
8111  DelimPos = x;
8112  break;
8113  }
8114  if(x == String.Length())
8115  {
8116  if(GiveMessages)
8117  {
8118  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8119  }
8120  Utilities->CallLogPop(543);
8121  return(-1);
8122  }
8123  }
8124  if(DelimPos == 1)
8125  {
8126  if(GiveMessages)
8127  {
8128  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8129  }
8130  Utilities->CallLogPop(544);
8131  return(-1);
8132  }
8133  if(DelimPos == String.Length())
8134  {
8135  if(GiveMessages)
8136  {
8137  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8138  }
8139  Utilities->CallLogPop(545);
8140  return(-1);
8141  }
8142  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8143  {
8144  if(GiveMessages)
8145  {
8146  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8147  }
8148  Utilities->CallLogPop(1508);
8149  return(-1);
8150  }
8151  int HLoc, VLoc;
8152 
8153  if(String.SubString(1, 1) != "N")
8154  {
8155  for(int x = 1; x < DelimPos; x++)
8156  {
8157  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8158  {
8159  if(GiveMessages)
8160  {
8161  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8162  }
8163  Utilities->CallLogPop(546);
8164  return(-1);
8165  }
8166  }
8167  }
8168  if(String.SubString(1, 1) == "N")
8169  {
8170  for(int x = 2; x < DelimPos; x++)
8171  {
8172  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8173  {
8174  if(GiveMessages)
8175  {
8176  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8177  }
8178  Utilities->CallLogPop(763);
8179  return(-1);
8180  }
8181  }
8182  }
8183  if(String.SubString(1, 1) == "N")
8184  {
8185  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8186  }
8187  else
8188  {
8189  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8190  }
8191  if(String.SubString(DelimPos + 1, 1) != "N")
8192  {
8193  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8194  {
8195  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8196  {
8197  if(GiveMessages)
8198  {
8199  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8200  }
8201  Utilities->CallLogPop(547);
8202  return(-1);
8203  }
8204  }
8205  }
8206  if(String.SubString(DelimPos + 1, 1) == "N")
8207  {
8208  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8209  {
8210  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8211  {
8212  if(GiveMessages)
8213  {
8214  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8215  }
8216  Utilities->CallLogPop(764);
8217  return(-1);
8218  }
8219  }
8220  }
8221  if(String.SubString(DelimPos + 1, 1) == "N")
8222  {
8223  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8224  }
8225  else
8226  {
8227  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8228  }
8229  THVPair HVPair(HLoc, VLoc);
8230  TTrackMapIterator TrackMapPtr;
8231 
8232  TrackMapPtr = TrackMap.find(HVPair);
8233  if(TrackMapPtr == TrackMap.end())
8234  {
8235  if(GiveMessages)
8236  {
8237  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8238  }
8239  Utilities->CallLogPop(548);
8240  return(-1);
8241  }
8242  Utilities->CallLogPop(549);
8243  return(TrackMapPtr->second);
8244  }
8245  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8246  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8247  {
8248  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8249  Utilities->CallLogPop(2481);
8250  return(-1);
8251  }
8252 }
8253 
8254 // ---------------------------------------------------------------------------
8255 
8256 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8257 /*
8258  True for linked properly at both ends
8259 */
8260 {
8261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8262  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8263  int HLoc = TrackElement.HLoc;
8264  int VLoc = TrackElement.VLoc;
8265 
8266  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8267  {
8268  Utilities->CallLogPop(1821);
8269  return(false);
8270  }
8271  if(TrackElement.SpeedTag == 129) // vertical footbridge
8272  {
8273  // check top connection
8274  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8275  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8276  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8277  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8278  {
8279  Utilities->CallLogPop(550);
8280  return(false);
8281  }
8282  // check bottom connection
8283  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8284  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8285  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8286  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8287  {
8288  Utilities->CallLogPop(551);
8289  return(false);
8290  }
8291  }
8292  if(TrackElement.SpeedTag == 145) // vertical underpass
8293  {
8294  // check top connection
8295  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8296  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8297  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8298  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8299  {
8300  Utilities->CallLogPop(2114);
8301  return(false);
8302  }
8303  // check bottom connection
8304  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8305  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8306  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8307  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8308  {
8309  Utilities->CallLogPop(2115);
8310  return(false);
8311  }
8312  }
8313  if(TrackElement.SpeedTag == 130) // hor footbridge
8314  {
8315  // check left connection
8316  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8317  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8318  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8319  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8320  {
8321  Utilities->CallLogPop(552);
8322  return(false);
8323  }
8324  // check right connection
8325  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8326  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8327  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8328  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8329  {
8330  Utilities->CallLogPop(553);
8331  return(false);
8332  }
8333  }
8334  if(TrackElement.SpeedTag == 146) // hor u'pass
8335  {
8336  // check left connection
8337  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8338  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8339  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8340  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8341  {
8342  Utilities->CallLogPop(2116);
8343  return(false);
8344  }
8345  // check right connection
8346  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8347  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8348  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8349  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8350  {
8351  Utilities->CallLogPop(2117);
8352  return(false);
8353  }
8354  }
8355  Utilities->CallLogPop(554);
8356  return(true);
8357 }
8358 
8359 // ---------------------------------------------------------------------------
8360 
8361 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8362 /*
8363  return true if the SpeedTag present in the map at H & V
8364 */
8365 {
8366  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8367  AnsiString(SpeedTag));
8368  if(InactiveTrack2MultiMap.empty())
8369  {
8370  Utilities->CallLogPop(555);
8371  return(false);
8372  }
8373  THVPair HVPair(HLoc, VLoc);
8375  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8376  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8377 
8378  if(HVRange.first == HVRange.second)
8379  {
8380  Utilities->CallLogPop(556);
8381  return(false);
8382  }
8383  else
8384  {
8385  HVIt1 = HVRange.first;
8386  }
8387  TTrackElement Temp1, Temp2; // test
8388 
8389  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8390  if(--HVRange.second != HVRange.first)
8391  {
8392  HVIt2 = HVRange.second;
8393  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8394  }
8395  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8396  HVIt2->second).SpeedTag == SpeedTag)))
8397  {
8398  Utilities->CallLogPop(557);
8399  return(true);
8400  }
8401  else
8402  {
8403  Utilities->CallLogPop(558);
8404  return(false);
8405  }
8406 }
8407 
8408 // ---------------------------------------------------------------------------
8409 
8410 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8411 /*
8412  return true if the SpeedTag present in the map at H & V
8413 */
8414 {
8415  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8416  AnsiString(SpeedTag));
8417  if(TrackMap.empty())
8418  {
8419  Utilities->CallLogPop(559);
8420  return(false);
8421  }
8422  THVPair HVPair(HLoc, VLoc);
8423  TTrackMapIterator End = TrackMap.end();
8424  TTrackMapIterator It = End;
8425 
8426  It = TrackMap.find(HVPair);
8427  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8428  {
8429  Utilities->CallLogPop(560);
8430  return(true);
8431  }
8432  else
8433  {
8434  Utilities->CallLogPop(561);
8435  return(false);
8436  }
8437 }
8438 
8439 // ---------------------------------------------------------------------------
8440 
8441 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8442 {
8443 /*
8444  General:
8445  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8446  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8447  a NamedNonStationLocation.
8448  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8449  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8450  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8451  platform at that location).
8452 
8453  Linked named location elements are those explained in TTrack::TTrack()
8454 
8455  Detail:
8456  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8457  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8458  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8459  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8460  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8461  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8462 
8463  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8464  this function a single element should be in the List (normally from the user's selection but can also be from
8465  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8466  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8467  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8468  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8469  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8470  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8471  moves them into the Map. At the end all linked elements are in the Map.
8472 
8473  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8474  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8475  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8476 */
8477 
8478 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8479 // Display->FileDiagnostics(TestString);//test
8480 
8481  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8482  AnsiString TestString1, TestString2; // test
8483 
8484  Track->LNDone2MultiMap.clear();
8485  if(LNPendingList.size() != 1)
8486  {
8487  throw Exception("LNPendingList size not 1 on entry");
8488  }
8489  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8490  bool FoundFlag = false, ErasedFlag = false;
8491  while(!LNPendingList.empty())
8492  {
8493  CurrentElementNumber = LNPendingList.front();
8494  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8495  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8496  int H = CurrentElement->HLoc;
8497  int V = CurrentElement->VLoc;
8498  int Tag = CurrentElement->SpeedTag;
8499  if(Tag == 76) // top plat
8500  {
8501  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8502  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8503  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8504  for(int x = 0; x < 25; x++)
8505  {
8506  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8507  {
8508  LNPendingList.insert(LNPendingList.end(), NewElement);
8509  }
8510  }
8511  }
8512  else if(Tag == 77) // bot plat
8513  {
8514  for(int x = 0; x < 25; x++)
8515  {
8516  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8517  {
8518  LNPendingList.insert(LNPendingList.end(), NewElement);
8519  }
8520  }
8521  }
8522  else if(Tag == 78) // l plat
8523  {
8524  for(int x = 0; x < 25; x++)
8525  {
8526  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8527  {
8528  LNPendingList.insert(LNPendingList.end(), NewElement);
8529  }
8530  }
8531  }
8532  else if(Tag == 79) // r plat
8533  {
8534  for(int x = 0; x < 25; x++)
8535  {
8536  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8537  {
8538  LNPendingList.insert(LNPendingList.end(), NewElement);
8539  }
8540  }
8541  }
8542  else if(Tag == 96) // conc
8543  {
8544  for(int x = 0; x < 28; x++)
8545  {
8546  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8547  {
8548  LNPendingList.insert(LNPendingList.end(), NewElement);
8549  }
8550  }
8551  }
8552  else if(Tag == 129) // vert footbridge
8553  {
8554  for(int x = 0; x < 8; x++)
8555  {
8556  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8557  {
8558  LNPendingList.insert(LNPendingList.end(), NewElement);
8559  }
8560  }
8561  }
8562  else if(Tag == 130) // hor footbridge
8563  {
8564  for(int x = 0; x < 8; x++)
8565  {
8566  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8567  {
8568  LNPendingList.insert(LNPendingList.end(), NewElement);
8569  }
8570  }
8571  }
8572  else if(Tag == 131) // named location
8573  {
8574  for(int x = 0; x < 4; x++)
8575  {
8576  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8577  {
8578  LNPendingList.insert(LNPendingList.end(), NewElement);
8579  }
8580  }
8581  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8582  {
8583  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8584  {
8585  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8586  if(GJTVPos > -1)
8587  {
8588  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8589  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8590  bool FoundFlag2 = false;
8591  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8592  if(FoundFlag2)
8593  {
8594  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8595  {
8596  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8597  {
8598  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8599  }
8600  }
8601  }
8602  }
8603  }
8604  }
8605  }
8606  else if(Tag == 145) // v u'pass
8607  {
8608  for(int x = 0; x < 8; x++)
8609  {
8610  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8611  {
8612  LNPendingList.insert(LNPendingList.end(), NewElement);
8613  }
8614  }
8615  }
8616  else if(Tag == 146) // h u'pass
8617  {
8618  for(int x = 0; x < 8; x++)
8619  {
8620  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8621  {
8622  LNPendingList.insert(LNPendingList.end(), NewElement);
8623  }
8624  }
8625  }
8626  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8627 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8628  if(AddingElements)
8629  {
8630  int HPos, VPos; // not used but needed for FindText function
8631  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8632  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8633  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8634  {
8635  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8636  if((ExistingName != "") && (ExistingName != LocationName))
8637  {
8638  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8639  {
8640  } // name not in LocationNameMultiMap, so don't erase from TextVector
8641  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8642  {
8643  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8644  {
8645  ;
8646  } // condition not used
8647 
8648  }
8649  }
8650  }
8651  }
8652  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8653  // track at that loc
8654  THVPair HVPair(H, V);
8655  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8656  LNDone2MultiMapEntry.first = HVPair;
8657  LNDone2MultiMapEntry.second = LNPendingList.front();
8658  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8659  LNPendingList.erase(LNPendingList.begin());
8660  }
8661 
8662 // search all name multimap for same name where corresponding active elements don't appear in
8663 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8664 
8665  TLocationNameMultiMapIterator SNIterator;
8666  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8667 
8668  if(SNRange.first != SNRange.second)
8669  {
8670  SNRange.first--; // now pointing to before the first
8671  SNRange.second--; // now pointing to the last
8672  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8673  {
8674  // Same elements are in Done map as in name map
8675  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8676  {
8677  ErasedFlag = true;
8678  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8679  TVIt->LocationName = "";
8680  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8681  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8682  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8683  {
8684  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8685  if(FoundFlag)
8686  {
8687  TrackElementAt(20, Position).LocationName = "";
8688  TrackElementAt(21, Position).ActiveTrackElementName = "";
8689  }
8690  }
8691  // erase name in name map
8692 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8693  }
8694  }
8695  }
8696  if(ErasedFlag)
8697  {
8699  }
8700  if(TrackFinished)
8701  {
8704  }
8705 // set here as well as in LinkTrack so don't have to link track just because a name added
8706 // if track not finished then will be set when track validated
8707 
8708 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8709 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8710 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8711 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8712 // so the error would be seen.
8713 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8714  std::pair<AnsiString, char>TempMapPair;
8715 
8716  ContinuationNameMap.clear();
8717  for(int x = 0; x < Track->TrackVectorSize(); x++)
8718  {
8719  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8720  {
8721  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8722  TempMapPair.second = 'x'; // unused
8723  ContinuationNameMap.insert(TempMapPair);
8724  }
8725  }
8726 //end of addition
8727  CheckLocationNameMultiMap(1); // test
8728  Utilities->CallLogPop(562);
8729 }
8730 
8731 // ---------------------------------------------------------------------------
8732 
8733 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8734 /*
8735  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8736  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8737 */
8738 {
8739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8740  AnsiString(SpeedTag));
8741  if(!NamedLocationElementAt(2, HLoc, VLoc))
8742  {
8743  Utilities->CallLogPop(948);
8744  return(false);
8745  }
8746  bool FoundFlag;
8747  int Position = -1;
8748  TIMPair IMPair;
8749 
8750  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8751  {
8752  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8753  if(FoundFlag)
8754  {
8755  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8756  {
8757  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8758  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8759  // don't allow duplicates in either list, or processing takes a lot longer
8760  {
8761  FoundElement = MapPos;
8762  Utilities->CallLogPop(563);
8763  return(true);
8764  }
8765  }
8766  }
8767  }
8768  else
8769  {
8770  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8771  if(FoundFlag)
8772  {
8773  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8774  {
8775  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8776  {
8777  FoundElement = IMPair.first;
8778  Utilities->CallLogPop(564);
8779  return(true);
8780  }
8781  }
8782  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8783  {
8784  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8785  {
8786  FoundElement = IMPair.second;
8787  Utilities->CallLogPop(565);
8788  return(true);
8789  }
8790  }
8791  }
8792  }
8793  Utilities->CallLogPop(566);
8794  return(false);
8795 }
8796 
8797 // ---------------------------------------------------------------------------
8798 
8799 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8800 /*
8801  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8802  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8803  with the new name
8804 */
8805 {
8806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8807  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8808 
8809  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8810  int HLoc = TrackElement->HLoc;
8811  int VLoc = TrackElement->VLoc;
8812  bool FoundFlag;
8813 
8814  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8815  // only have timetable names for adjacent platforms & named locations
8816  {
8817  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8818  if(FoundFlag)
8819  {
8820  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8821  }
8822  }
8823  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8824 
8825  if(ErrorString != "")
8826  {
8827  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8828  }
8829  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8830  CheckLocationNameMultiMap(2); // test
8831  Utilities->CallLogPop(567);
8832 }
8833 
8834 // ---------------------------------------------------------------------------
8835 
8836 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8837 /*
8838  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8839 */
8840 {
8841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8842  if(LNDone2MultiMap.empty())
8843  {
8844  Utilities->CallLogPop(568);
8845  return(false);
8846  }
8847  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8848 
8849  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8850  {
8851  if(LNDone2MultiMapIterator->second == MapPos)
8852  {
8853  Utilities->CallLogPop(569);
8854  return(true);
8855  }
8856  }
8857  Utilities->CallLogPop(570);
8858  return(false);
8859 }
8860 
8861 // ---------------------------------------------------------------------------
8862 
8863 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8864 /*
8865  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8866 */
8867 {
8868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8869  if(LNPendingList.empty())
8870  {
8871  Utilities->CallLogPop(571);
8872  return(false);
8873  }
8874  TLNPendingListIterator LNPendingListIterator;
8875 
8876  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8877  {
8878  if(*LNPendingListIterator == MapPos)
8879  {
8880  Utilities->CallLogPop(572);
8881  return(true);
8882  }
8883  }
8884  Utilities->CallLogPop(573);
8885  return(false);
8886 }
8887 
8888 // ---------------------------------------------------------------------------
8889 
8890 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8891 /*
8892  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8893 */
8894 {
8895  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8896  THVPair HVPair(HLoc, VLoc);
8897  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8898  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8899 
8900  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8901  {
8902  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8903  {
8904  Utilities->CallLogPop(574);
8905  return(true);
8906  }
8907  }
8908  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8909  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8910  {
8911  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8912  {
8913  Utilities->CallLogPop(575);
8914  return(true);
8915  }
8916  }
8917  Utilities->CallLogPop(576);
8918  return(false);
8919 }
8920 
8921 // ---------------------------------------------------------------------------
8922 
8923 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8924 {
8925  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8926  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8927  {
8928  Utilities->CallLogPop(1953);
8929  return(true);
8930  }
8931  Utilities->CallLogPop(1954);
8932  return(false);
8933 }
8934 
8935 // ---------------------------------------------------------------------------
8936 
8937 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8938 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8939 //program and used when try to save as a .rly file
8940 {
8941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8944  if(LocationNameMultiMap.empty()) //no names so no duplicates
8945  {
8946  Utilities->CallLogPop(2254);
8947  return(false);
8948  }
8949  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8950  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8951  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8952  {
8954  {
8955  if(GiveMessage)
8956  {
8957  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8958  }
8959  Utilities->CallLogPop(2255);
8960  return(true);
8961  }
8962  }
8963  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8964  {
8965  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8966  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8967  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8968  {
8970  {
8971  if(GiveMessage)
8972  {
8973  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8974  }
8975  Utilities->CallLogPop(2256);
8976  return(true);
8977  }
8978  }
8979  }
8980  Utilities->CallLogPop(2257);
8981  return(false); //OK, no duplicates
8982 }
8983 
8984 // ---------------------------------------------------------------------------
8985 
8987 {
8988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8989  THVPair HVPair;
8990  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8991  //for use in the duplicate check
8992  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8993  {
8994  if(LNMMIt->second < 0) //active track element
8995  {
8996  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8997  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8998  }
8999  else //inactive track element
9000  {
9001  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
9002  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
9003  }
9004  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
9005  }
9006  //All HVPairs now present in HVPairsLinkedMap for the specific location name
9007 
9008  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
9009  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
9010  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
9011 
9012  std::list<THVPair> HVLinkedList;
9013 
9014  //set the first value to true and add it to the list
9015  HVPairsLinkedMap.begin()->second = true;
9016  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
9017  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
9018  //examination
9019  THVPair HVPairUnderExamination;
9020  THVPairsLinkedMap::iterator HVPLMIt;
9021  THVPair HVPairNew;
9022  while(!HVLinkedList.empty())
9023  {
9024  HVPairUnderExamination = HVLinkedList.front();
9025  HVLinkedList.pop_front();
9026  HVPairNew.first = HVPairUnderExamination.first;
9027  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
9028  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9029  if(HVPLMIt != HVPairsLinkedMap.end())
9030  {
9031  if(!HVPLMIt->second)
9032  {
9033  HVLinkedList.push_back(HVPLMIt->first);
9034  }
9035  HVPLMIt->second = true;
9036  }
9037  HVPairNew.first = HVPairUnderExamination.first - 1;
9038  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
9039  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9040  if(HVPLMIt != HVPairsLinkedMap.end())
9041  {
9042  if(!HVPLMIt->second)
9043  {
9044  HVLinkedList.push_back(HVPLMIt->first);
9045  }
9046  HVPLMIt->second = true;
9047  }
9048  HVPairNew.first = HVPairUnderExamination.first;
9049  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
9050  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9051  if(HVPLMIt != HVPairsLinkedMap.end())
9052  {
9053  if(!HVPLMIt->second)
9054  {
9055  HVLinkedList.push_back(HVPLMIt->first);
9056  }
9057  HVPLMIt->second = true;
9058  }
9059  HVPairNew.first = HVPairUnderExamination.first + 1;
9060  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
9061  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9062  if(HVPLMIt != HVPairsLinkedMap.end())
9063  {
9064  if(!HVPLMIt->second)
9065  {
9066  HVLinkedList.push_back(HVPLMIt->first);
9067  }
9068  HVPLMIt->second = true;
9069  }
9070  }
9071 
9072  //at the end if any have a false bool then the name is duplicated so return false
9073  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9074  {
9075  if(!HVPLMIt->second)
9076  {
9077  Utilities->CallLogPop(2258);
9078  return(false);
9079  }
9080  }
9081  Utilities->CallLogPop(2259);
9082  return(true);
9083 }
9084 
9085 // ---------------------------------------------------------------------------
9086 
9087 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9088 /*
9089  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9090 */
9091 
9092 {
9093  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9094  if(LocationName == "")
9095  {
9096  Utilities->CallLogPop(577);
9097  return(false);
9098  }
9099 // new for v0.2b
9100 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9102  {
9103  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9104  ActiveTrackElementNameMap.clear();
9105  for(unsigned int x = 0; x < TrackVector.size(); x++)
9106  {
9107  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9108  == ContinuationNameMap.end())
9109  {
9110  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9111  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9112  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9113  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9114  }
9115  }
9117  }
9118  Utilities->CallLogPop(578);
9119  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9120 // end of new section
9121 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9122 }
9123 
9124 // ---------------------------------------------------------------------------
9125 
9126 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9127 /*
9128  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9129  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9130  new names in the vectors.
9131 */
9132 {
9133  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9134  bool FoundFlag, ErasedFlag = false;
9135  TLocationNameMultiMapIterator SNIterator;
9136  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9137 
9138  if(SNRange.first != SNRange.second)
9139  {
9140  ErasedFlag = true;
9141  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9142  {
9143  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9144  TVIt->LocationName = "";
9145  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9146  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9147  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9148  {
9149  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9150  if(FoundFlag)
9151  {
9152  TrackElementAt(25, Position).LocationName = "";
9153  TrackElementAt(26, Position).ActiveTrackElementName = "";
9154  }
9155  }
9156  }
9157  }
9158  if(ErasedFlag)
9159  {
9161  }
9162  CheckLocationNameMultiMap(3); // test
9163  Utilities->CallLogPop(579);
9164 }
9165 
9166 // ---------------------------------------------------------------------------
9167 
9168 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9169 /*
9170  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9171  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9172  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9173  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9174  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9175  it is entered into LNPendingList and EnterLocationName sets all others.
9176 */
9177 {
9178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9179  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9180  LNPendingList.clear();
9181  AnsiString LocationName;
9182  int MapPos;
9183  bool FoundFlag = 0;
9184 
9185 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9186  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9187  if(FoundFlag)
9188  {
9189  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9190  if(LocationName != "")
9191  {
9192  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9193  EnterLocationName(13, LocationName, true);
9194  Utilities->CallLogPop(2251);
9195  return;
9196  }
9197  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9198  if(LocationName != "")
9199  {
9200  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9201  EnterLocationName(14, LocationName, true);
9202  Utilities->CallLogPop(2252);
9203  return;
9204  }
9205  }
9206 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9207 
9208  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9209  if(FoundFlag)
9210  {
9211  LocationName = TrackElementAt(1004, Position).LocationName;
9212  if(LocationName != "")
9213  {
9214  int ModifiedPosition = -1 - Position;
9215  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9216  EnterLocationName(15, LocationName, true);
9217  Utilities->CallLogPop(2253);
9218  return;
9219  }
9220  }
9221  if(SpeedTag == 76) // top plat
9222  {
9223  for(int x = 0; x < 25; x++)
9224  {
9225  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9226  {
9227  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9228  EnterLocationName(3, LocationName, true);
9229  break;
9230  }
9231  }
9232  }
9233  else if(SpeedTag == 77) // bot plat
9234  {
9235  for(int x = 0; x < 25; x++)
9236  {
9237  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9238  {
9239  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9240  EnterLocationName(4, LocationName, true);
9241  break;
9242  }
9243  }
9244  }
9245  else if(SpeedTag == 78) // l plat
9246  {
9247  for(int x = 0; x < 25; x++)
9248  {
9249  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9250  {
9251  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9252  EnterLocationName(5, LocationName, true);
9253  break;
9254  }
9255  }
9256  }
9257  else if(SpeedTag == 79) // r plat
9258  {
9259  for(int x = 0; x < 25; x++)
9260  {
9261  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9262  {
9263  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9264  EnterLocationName(6, LocationName, true);
9265  break;
9266  }
9267  }
9268  }
9269  else if(SpeedTag == 96) // conc
9270  {
9271  for(int x = 0; x < 28; x++)
9272  {
9273  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9274  {
9275  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9276  EnterLocationName(7, LocationName, true);
9277  break;
9278  }
9279  }
9280  }
9281  else if(SpeedTag == 129) // vert footbridge
9282  {
9283  for(int x = 0; x < 8; x++)
9284  {
9285  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9286  {
9287  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9288  EnterLocationName(8, LocationName, true);
9289  break;
9290  }
9291  }
9292  }
9293  else if(SpeedTag == 130) // hor footbridge
9294  {
9295  for(int x = 0; x < 8; x++)
9296  {
9297  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9298  {
9299  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9300  EnterLocationName(9, LocationName, true);
9301  break;
9302  }
9303  }
9304  }
9305  else if(SpeedTag == 145) // vert u'pass
9306  {
9307  for(int x = 0; x < 8; x++)
9308  {
9309  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9310  {
9311  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9312  EnterLocationName(11, LocationName, true);
9313  break;
9314  }
9315  }
9316  }
9317  else if(SpeedTag == 146) // hor u'pass
9318  {
9319  for(int x = 0; x < 8; x++)
9320  {
9321  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9322  {
9323  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9324  EnterLocationName(12, LocationName, true);
9325  break;
9326  }
9327  }
9328  }
9329  else if(SpeedTag == 131) // named location
9330  {
9331  for(int x = 0; x < 4; x++)
9332  {
9333  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9334  {
9335  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9336  EnterLocationName(10, LocationName, true);
9337  Utilities->CallLogPop(2657);
9338  return;
9339  }
9340  }
9341  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9342  {
9343  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9344  {
9345  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9346  if(GJTVPos > -1)
9347  {
9348  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9349  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9350  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9351  bool FoundFlag2 = false;
9352  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9353  if(FoundFlag2)
9354  {
9355  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9356  {
9357  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9358  EnterLocationName(16, LocationName, true);
9359  }
9360  }
9361  }
9362  }
9363  }
9364  }
9365 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9366  Utilities->CallLogPop(580);
9367 }
9368 
9369 // ---------------------------------------------------------------------------
9370 
9371 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9372 /*
9373  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9374  true if a LocationName is found, and also returns the name and the adjusted vector position.
9375 */
9376 {
9377  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9378  AnsiString(SpeedTag));
9379  bool FoundFlag;
9380  TIMPair IMPair;
9381  TTrackVectorIterator TempElement;
9382  int Position;
9383 
9384  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9385  if(FoundFlag)
9386  {
9387  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9388  {
9389  TempElement = InactiveTrackVector.begin() + IMPair.first;
9390  if(TempElement->LocationName != "")
9391  {
9392  LocationName = TempElement->LocationName;
9393  FoundElement = IMPair.first;
9394  Utilities->CallLogPop(581);
9395  return(true);
9396  }
9397  }
9398  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9399  {
9400  TempElement = InactiveTrackVector.begin() + IMPair.second;
9401  if(TempElement->LocationName != "")
9402  {
9403  LocationName = TempElement->LocationName;
9404  FoundElement = IMPair.second;
9405  Utilities->CallLogPop(582);
9406  return(true);
9407  }
9408  }
9409  }
9410  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9411  if(FoundFlag)
9412  {
9413  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9414  {
9415  TempElement = TrackVector.begin() + Position;
9416  if(TempElement->LocationName != "")
9417  {
9418  LocationName = TempElement->LocationName;
9419  FoundElement = -1 - Position;
9420  Utilities->CallLogPop(583);
9421  return(true);
9422  }
9423  }
9424  }
9425  Utilities->CallLogPop(584);
9426  return(false);
9427 }
9428 
9429 // ---------------------------------------------------------------------------
9430 
9431 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9432 {
9433 // check quantity in map & vectors match
9434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9435  unsigned int Count = 0;
9436 
9437  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9438  {
9439  Utilities->CallLogPop(2059);
9440  return;
9441  }
9442  AnsiString SName, TName, ErrorString;
9443 
9444  for(unsigned int x = 0; x < TrackVector.size(); x++)
9445  {
9446  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9447  {
9448  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9449  {
9450  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9451  AnsiString(Caller));
9452  }
9453  Count++;
9454  }
9455  }
9456  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9457  {
9458  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9459  {
9460  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9461  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9462  {
9463  throw Exception
9464  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9465  AnsiString(Caller));
9466  }
9467  Count++;
9468  }
9469  }
9470  if(LocationNameMultiMap.size() != Count)
9471  {
9472  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9473  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9474  }
9475 // check all entries in both vectors match entries in name multimap
9477 
9478  for(unsigned int x = 0; x < TrackVector.size(); x++)
9479  {
9480  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9481  {
9482  SName = TrackElementAt(1365, x).LocationName;
9483  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9484  if(ErrorString != "")
9485  {
9486  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9487  }
9488  if(SNIt->second != -1 - (int)x)
9489  {
9490  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9491  AnsiString(Caller));
9492  }
9493  }
9494  // check corresponding platform for all Timetable entries that aren't empty
9495  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9496  TIMPair IMPair;
9497  bool FoundFlag = false;
9498  if(TName != "")
9499  {
9500  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9501  if(FoundFlag)
9502  {
9503  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9505  {
9506  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9507  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9508  }
9509  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9510  {
9511  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9512  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9513  AnsiString(Caller));
9514  }
9515  }
9516  else
9517  {
9518  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9519  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9520  }
9521  }
9522  }
9523  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9524  {
9525  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9526  {
9527  SName = InactiveTrackElementAt(148, x).LocationName;
9528  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9529  if(ErrorString != "")
9530  {
9531  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9532  }
9533  if(SNIt->second != (int)x)
9534  {
9535  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9536  AnsiString(Caller));
9537  }
9538  }
9539  }
9540  Utilities->CallLogPop(585);
9541 }
9542 
9543 // ---------------------------------------------------------------------------
9544 
9546  AnsiString &ErrorString)
9547 {
9548 /*
9549  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9550  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9551  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9552 */
9553  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9554  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9555  ErrorString = "";
9556  bool FoundFlag = false;
9557  TLocationNameMultiMapIterator SNIterator;
9558  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9559 
9560  if(SNRange.first == SNRange.second)
9561  {
9562  ErrorString = "Error, Name " + LocationName + " not found in map";
9563  Utilities->CallLogPop(586);
9564  return(SNRange.first);
9565  }
9566  else
9567  {
9568  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9569  {
9570  if(SNIterator->second < 0)
9571  {
9572  int TVPos = -1 - SNIterator->second;
9573  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9574  if(TVIt == TrackElement)
9575  {
9576  FoundFlag = true;
9577  Utilities->CallLogPop(587);
9578  return(SNIterator);
9579  }
9580  }
9581  else
9582  {
9583  int ITVPos = SNIterator->second;
9584  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9585  if(ITVIt == TrackElement)
9586  {
9587  FoundFlag = true;
9588  Utilities->CallLogPop(588);
9589  return(SNIterator);
9590  }
9591  }
9592  }
9593  }
9594  if(!FoundFlag)
9595  {
9596  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9597  }
9598  Utilities->CallLogPop(589);
9599  return(SNIterator);
9600 }
9601 
9602 // ---------------------------------------------------------------------------
9603 
9604 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9605 {
9606 /*
9607  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9608  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9609 */
9610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9611  TLocationNameMultiMapEntry LocationNameEntry;
9612 
9613  LocationNameEntry.first = NewName;
9614  LocationNameEntry.second = SNIterator->second;
9615  LocationNameMultiMap.erase(SNIterator);
9616  LocationNameMultiMap.insert(LocationNameEntry);
9617  Utilities->CallLogPop(590);
9618 }
9619 
9620 // ---------------------------------------------------------------------------
9621 
9623 {
9624 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9626  if(Position < 0) // footcrossing
9627  {
9628  int TruePos = -1 - Position;
9629  // new check at v0.2b
9630  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9631  {
9632  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9633  }
9634  Utilities->CallLogPop(591);
9635  return (TrackVector.begin() + TruePos);
9636  }
9637  else
9638  {
9639  // new check at v0.2b
9640  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9641  {
9642  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9643  }
9644  Utilities->CallLogPop(592);
9645  return (InactiveTrackVector.begin() + Position);
9646  }
9647 }
9648 
9649 // ---------------------------------------------------------------------------
9650 
9651 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9652 {
9653 /*
9654  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9655  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9656  LocationNameMultiMap.
9657 */
9658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9659  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9660  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9661 
9662  if(!InactiveTrack2MultiMap.empty())
9663  {
9664  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9665  InactiveTrack2MultiMapIterator++)
9666  {
9667  if(InactiveTrack2MultiMapIterator->second > VecPos)
9668  {
9669  InactiveTrack2MultiMapIterator->second--;
9670  }
9671  // can't be == VecPos as that position erased
9672  }
9673  }
9674  if(!LocationNameMultiMap.empty())
9675  {
9676  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9677  LocationNameMultiMapIterator++)
9678  {
9679  if(LocationNameMultiMapIterator->second < 0)
9680  {
9681  continue; // deal with TrackVectors separately
9682  }
9683  if(LocationNameMultiMapIterator->second > (int)VecPos)
9684  {
9685  LocationNameMultiMapIterator->second--;
9686  }
9687  }
9688  }
9689  Utilities->CallLogPop(593);
9690 }
9691 
9692 // ---------------------------------------------------------------------------
9693 
9694 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9695 {
9696 /*
9697  After an element has been erased from the track vector, all the later elements are moved down one. This function
9698  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9699  LocationNameMultiMap.
9700 */
9701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9702  TTrackMapIterator TrackMapIterator;
9703  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9704 
9705  if(!TrackMap.empty())
9706  {
9707  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9708  {
9709  if(TrackMapIterator->second > VecPos)
9710  {
9711  TrackMapIterator->second--;
9712  }
9713  // can't be == VecPos as that position erased
9714  }
9715  }
9716  if(!LocationNameMultiMap.empty())
9717  {
9718  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9719  LocationNameMultiMapIterator++)
9720  {
9721  if(LocationNameMultiMapIterator->second >= 0)
9722  {
9723  continue; // deal with InactiveTrackVectors separately
9724  }
9725  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9726  // Val -1 -2 -3 -4 -5 -6 -7 -8
9727  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9728  {
9729  LocationNameMultiMapIterator->second++;
9730  }
9731  }
9732  }
9733  for(unsigned int x = 0; x < TrackVector.size(); x++)
9734  {
9735  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9736  if(TkEl.TrackType == GapJump)
9737  {
9738  // position 0 is the gap
9739  if(TkEl.Conn[0] == int(VecPos))
9740  {
9741  TkEl.Conn[0] = -1; // connected to a deleted gap
9742  continue;
9743  }
9744  if(TkEl.Conn[0] > int(VecPos))
9745  {
9746  TkEl.Conn[0]--;
9747  }
9748  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9749  {
9750  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9751  {
9752  TkEl.Conn[0] = -1;
9753  }
9754  }
9755  }
9756  }
9757  Utilities->CallLogPop(1433);
9758 }
9759 
9760 // ---------------------------------------------------------------------------
9761 
9763 /*
9764  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9765  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9766  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9767  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9768  running from -1 to -1 - n
9769 */
9770 {
9771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9772  LocationNameMultiMap.clear();
9773  TLocationNameMultiMapEntry LocationNameEntry;
9774  TTrackElement TrackElement;
9775 
9776  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9777  {
9778  TrackElement = TrackElementAt(1376, TVPos);
9779  if(TrackElement.FixedNamedLocationElement)
9780  {
9781  LocationNameEntry.first = TrackElement.LocationName;
9782  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9783  LocationNameMultiMap.insert(LocationNameEntry);
9784  }
9785  }
9786 
9787  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9788  {
9789  TrackElement = InactiveTrackElementAt(149, ITVPos);
9790  if(TrackElement.FixedNamedLocationElement)
9791  {
9792  LocationNameEntry.first = TrackElement.LocationName;
9793  LocationNameEntry.second = ITVPos;
9794  LocationNameMultiMap.insert(LocationNameEntry);
9795  }
9796  }
9797  Utilities->CallLogPop(594);
9798 }
9799 
9800 // ---------------------------------------------------------------------------
9801 
9803 // Return true if there is a named location present in the railway
9804 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9805 {
9806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9807  TTrackVectorIterator ITVI;
9808 
9809  if(InactiveTrackVector.empty())
9810  {
9811  Utilities->CallLogPop(1343);
9812  return(false);
9813  }
9814  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9815  {
9816  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9817  {
9818  Utilities->CallLogPop(1404);
9819  return(true);
9820  }
9821  }
9822  Utilities->CallLogPop(1344);
9823  return(false);
9824 }
9825 
9826 // ---------------------------------------------------------------------------
9827 
9829 /*
9830  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9831 */
9832 {
9833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9834 // ResetDistanceElements(6);
9835  for(unsigned int x = 0; x < TrackVector.size(); x++)
9836  {
9837  TTrackElement &TE = TrackElementAt(718, x);
9840  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9841  {
9844  }
9845  }
9846 /* old function
9847  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9848  {
9849  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9850  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9851  }
9852  else
9853  {
9854  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9855  }
9856  }
9857 */
9858  Utilities->CallLogPop(617);
9859 }
9860 
9861 // ---------------------------------------------------------------------------
9862 
9864 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLengthandSpeed.
9865 {
9866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthandSpeedMarker");
9867  for(unsigned int x = 0; x < TrackVector.size(); x++)
9868  {
9869  TTrackElement TempElement = TrackElementAt(1377, x);
9870  if(TempElement.Length01 > -1)
9871  {
9872  MarkOneLengthandSpeed(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9873  }
9874  if(TempElement.Length23 > -1)
9875  {
9876  MarkOneLengthandSpeed(2, TempElement, false, Disp);
9877  }
9878  }
9879  Disp->Update();
9880  Utilities->CallLogPop(618);
9881 }
9882 
9883 // ---------------------------------------------------------------------------
9884 void TTrack::LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp) //Length false -> speed heatmap //unused //added at v2.22.0
9885 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using OneLengthOrSpeedHeatMapColour
9886 {
9887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthOrSpeedHeatMap");
9888  for(unsigned int x = 0; x < TrackVector.size(); x++)
9889  {
9890  TTrackElement TempElement = TrackElementAt(1689, x);
9891  if(((TempElement.HLoc - Display->DisplayOffsetH) >= 0) && ((TempElement.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
9892  ((TempElement.VLoc - Display->DisplayOffsetV) >= 0) && ((TempElement.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
9893  {//only plot if onscreen as takes quite a long time
9894  if(TempElement.Length01 > -1)
9895  {
9896  OneLengthOrSpeedHeatMapColour(8, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9897  }
9898  if(TempElement.Length23 > -1)
9899  {
9900  OneLengthOrSpeedHeatMapColour(9, TempElement, false, Disp);
9901  }
9902  }
9903  }
9904  Disp->Update();
9905  Utilities->CallLogPop(2722);
9906 }
9907 
9908 // ---------------------------------------------------------------------------
9909 
9910 void TTrack::OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp) //added at v2.22.0
9911 
9912 {
9913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneLengthOrSpeedHeatMapColour," + TrackElement.LogTrack(8) + "," +
9914  AnsiString((short)FirstTrack));
9915 
9916  int EXArray[16][2] =
9917  {{4, 6}, {2, 8}, // horizontal & vertical
9918  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9919  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9920  {1, 9}, {3, 7}}; // forward & reverse diagonals
9921 
9922  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink; //BrNum = bridge number, GrNum = graphic number
9923  Graphics::TBitmap *Bitmap;
9924  int Length;
9925  int Speed;
9926 
9927  if(FirstTrack)
9928  {
9929  InLink = TrackElement.Link[0];
9930  OutLink = TrackElement.Link[1];
9931  Length = TrackElement.Length01;
9932  Speed = TrackElement.SpeedLimit01;
9933  }
9934  else
9935  {
9936  InLink = TrackElement.Link[2];
9937  OutLink = TrackElement.Link[3];
9938  Length = TrackElement.Length23;
9939  Speed = TrackElement.SpeedLimit23;
9940  }
9941  for(int x = 0; x < 16; x++)
9942  {
9943  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9944  {
9945  Index = x;
9946  }
9947  }
9948  if(Index == -1)
9949  {
9950  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
9951  }
9952 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9953  the graphic for each of which is different because of the shape of the overbridge. The basic
9954  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9955  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9956  Note that the underbridge track always uses links 2 & 3
9957  int BrEXArray[24][2] = {
9958  {4,6},{2,8},{1,9},{3,7},
9959  {1,9},{3,7},{1,9},{3,7},
9960  {2,8},{4,6},{2,8},{4,6}
9961 */
9962 
9963  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
9964  {
9965  if(Index == 1)
9966  {
9967  if(TrackElement.SpeedTag == 49)
9968  {
9969  BrNum = 1 + 16;
9970  }
9971  else if(TrackElement.SpeedTag == 54)
9972  {
9973  BrNum = 8 + 16;
9974  }
9975  else if(TrackElement.SpeedTag == 55)
9976  {
9977  BrNum = 10 + 16;
9978  }
9979  }
9980  else if(Index == 0)
9981  {
9982  if(TrackElement.SpeedTag == 48)
9983  {
9984  BrNum = 0 + 16;
9985  }
9986  else if(TrackElement.SpeedTag == 58)
9987  {
9988  BrNum = 11 + 16;
9989  }
9990  else if(TrackElement.SpeedTag == 59)
9991  {
9992  BrNum = 9 + 16;
9993  }
9994  }
9995  else if(Index == 14)
9996  {
9997  if(TrackElement.SpeedTag == 50)
9998  {
9999  BrNum = 2 + 16;
10000  }
10001  else if(TrackElement.SpeedTag == 52)
10002  {
10003  BrNum = 4 + 16;
10004  }
10005  else if(TrackElement.SpeedTag == 57)
10006  {
10007  BrNum = 6 + 16;
10008  }
10009  }
10010  else if(Index == 15)
10011  {
10012  if(TrackElement.SpeedTag == 51)
10013  {
10014  BrNum = 3 + 16;
10015  }
10016  else if(TrackElement.SpeedTag == 53)
10017  {
10018  BrNum = 7 + 16;
10019  }
10020  else if(TrackElement.SpeedTag == 56)
10021  {
10022  BrNum = 5 + 16;
10023  }
10024  }
10025  }
10026  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10027  {
10028  GrNum = BrNum;
10029  }
10030  else
10031  {
10032  GrNum = Index;
10033  }
10034 
10035 //get basic track bitmap
10036  if(GrNum > 15) // underbridge
10037  {
10038  Bitmap = RailGraphics->BridgeGraphicsPtr[GrNum - 16];
10039  }
10040  else
10041  {
10042  Bitmap = RailGraphics->LinkGraphicsPtr[GrNum];
10043  }
10044  if(TrackElement.SpeedTag == 64)
10045  {
10046  Bitmap = RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10047  }
10048  if(TrackElement.SpeedTag == 65)
10049  {
10050  Bitmap = RailGraphics->LinkGraphicsPtr[17];
10051  }
10052  if(TrackElement.SpeedTag == 66)
10053  {
10054  Bitmap = RailGraphics->LinkGraphicsPtr[18];
10055  }
10056  if(TrackElement.SpeedTag == 67)
10057  {
10058  Bitmap = RailGraphics->LinkGraphicsPtr[19];
10059  }
10060  if(TrackElement.SpeedTag == 80)
10061  {
10062  Bitmap = RailGraphics->LinkGraphicsPtr[20]; // intercept continuations to show the dots
10063  }
10064  if(TrackElement.SpeedTag == 81)
10065  {
10066  Bitmap = RailGraphics->LinkGraphicsPtr[21];
10067  }
10068  if(TrackElement.SpeedTag == 82)
10069  {
10070  Bitmap = RailGraphics->LinkGraphicsPtr[22];
10071  }
10072  if(TrackElement.SpeedTag == 83)
10073  {
10074  Bitmap = RailGraphics->LinkGraphicsPtr[23];
10075  }
10076  if(TrackElement.SpeedTag == 84)
10077  {
10078  Bitmap = RailGraphics->LinkGraphicsPtr[24];
10079  }
10080  if(TrackElement.SpeedTag == 85)
10081  {
10082  Bitmap = RailGraphics->LinkGraphicsPtr[25];
10083  }
10084  if(TrackElement.SpeedTag == 86)
10085  {
10086  Bitmap = RailGraphics->LinkGraphicsPtr[26];
10087  }
10088  if(TrackElement.SpeedTag == 87)
10089  {
10090  Bitmap = RailGraphics->LinkGraphicsPtr[27];
10091  }
10092  if(TrackElement.SpeedTag == 129)
10093  {
10094  Bitmap = RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
10095  }
10096  if(TrackElement.SpeedTag == 130)
10097  {
10098  Bitmap = RailGraphics->LinkGraphicsPtr[29];
10099  }
10100 
10101 // RailGraphics->HeatMapGraphic->Assign(Bitmap); //make a copy prior to colouring <- no good, copies bits per pixel too
10102  TRect Rect(0,0,16,16);
10103  RailGraphics->HeatMapGraphic->Canvas->CopyRect(Rect, Bitmap->Canvas, Rect); //this is better, high colour resolution retained
10104  RailGraphics->HeatMapGraphic->TransparentColor = Utilities->clTransparent;
10105  //determine color required
10106  int Red, Green, Blue; //int values will be between 0 & 255
10107  int *R = &Red, *G = &Green, *B = &Blue;
10108  TColor Col;
10109  float Len, Spd;
10110  if(LengthHeatMapFlag)
10111  {
10112  if(Utilities->RedLowFlag)
10113  {
10114  Len = Length/10;
10115  }
10116  else
10117  {
10118  Len = 3000/Length;
10119  }
10120  RailGraphics->GetHeatMapColor(0, (Ln(Len))/5.704, R, G, B); //Len/10 makes range 1 to limit of 300, representing 3000km per element {3000/Len] for reverse spectrum
10121  Col = TColor((65536 * Blue) + (256 * Green) + Red); //5.704 normalises Ln range to between 0 & 1
10123  } //use ChangeForegroundColour2 as faster
10124  else if (SpeedHeatMapFlag)
10125  {
10126  if(Utilities->RedLowFlag)
10127  {
10128  Spd = Speed/10;
10129  }
10130  else
10131  {
10132  Spd = 400/Speed;
10133  }
10134  RailGraphics->GetHeatMapColor(1, (Ln(Spd))/3.691, R, G, B); //Spd/10 makes range 1 to limit of 40, representing 400km/h [400/Spd] for reverse spectrum
10135  Col = TColor((65536 * Blue) + (256 * Green) + Red); //3.691 normalises Ln range to between 0 & 1
10137  } //use ChangeForegroundColour2 as faster
10138  else
10139  {
10140  Utilities->CallLogPop(2721);
10141  return;
10142  }
10143  Disp->PlotOutput(289, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->HeatMapGraphic);
10144  Utilities->CallLogPop(2723);
10145 }
10146 
10147 // ---------------------------------------------------------------------------
10148 
10149 void TTrack::MarkOneLengthandSpeed(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
10150 /*
10151  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
10152  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
10153  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
10154  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
10155  track as indicated by FirstTrack (true for track01 & false for track23).
10156 */
10157 {
10158  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLengthandSpeed," + TrackElement.LogTrack(8) + "," +
10159  AnsiString((short)FirstTrack));
10160  bool LengthDifferent = false, SpeedDifferent = false; //BrNum = bridge number, GrNum = graphic number
10161 
10162  if(IsElementDefaultLengthAndSpeed(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
10163  {
10164  Utilities->CallLogPop(619);
10165  return;
10166  }
10167  int EXArray[16][2] =
10168  {{4, 6}, {2, 8}, // horizontal & vertical
10169  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
10170  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
10171  {1, 9}, {3, 7}}; // forward & reverse diagonals
10172 
10173  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
10174  Graphics::TBitmap *Bitmap;
10175 
10176  if(FirstTrack)
10177  {
10178  InLink = TrackElement.Link[0];
10179  OutLink = TrackElement.Link[1];
10180  }
10181  else
10182  {
10183  InLink = TrackElement.Link[2];
10184  OutLink = TrackElement.Link[3];
10185  }
10186  for(int x = 0; x < 16; x++)
10187  {
10188  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
10189  {
10190  Index = x;
10191  }
10192  }
10193  if(Index == -1)
10194  {
10195  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
10196  }
10197 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
10198  the graphic for each of which is different because of the shape of the overbridge. The basic
10199  entry/exit value is computed above, and this used to select only from elements with that entry/exit
10200  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
10201  Note that the underbridge track always uses links 2 & 3
10202  int BrEXArray[24][2] = {
10203  {4,6},{2,8},{1,9},{3,7},
10204  {1,9},{3,7},{1,9},{3,7},
10205  {2,8},{4,6},{2,8},{4,6}
10206 */
10207  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
10208  {
10209  if(Index == 1)
10210  {
10211  if(TrackElement.SpeedTag == 49)
10212  {
10213  BrNum = 1 + 16;
10214  }
10215  else if(TrackElement.SpeedTag == 54)
10216  {
10217  BrNum = 8 + 16;
10218  }
10219  else if(TrackElement.SpeedTag == 55)
10220  {
10221  BrNum = 10 + 16;
10222  }
10223  }
10224  else if(Index == 0)
10225  {
10226  if(TrackElement.SpeedTag == 48)
10227  {
10228  BrNum = 0 + 16;
10229  }
10230  else if(TrackElement.SpeedTag == 58)
10231  {
10232  BrNum = 11 + 16;
10233  }
10234  else if(TrackElement.SpeedTag == 59)
10235  {
10236  BrNum = 9 + 16;
10237  }
10238  }
10239  else if(Index == 14)
10240  {
10241  if(TrackElement.SpeedTag == 50)
10242  {
10243  BrNum = 2 + 16;
10244  }
10245  else if(TrackElement.SpeedTag == 52)
10246  {
10247  BrNum = 4 + 16;
10248  }
10249  else if(TrackElement.SpeedTag == 57)
10250  {
10251  BrNum = 6 + 16;
10252  }
10253  }
10254  else if(Index == 15)
10255  {
10256  if(TrackElement.SpeedTag == 51)
10257  {
10258  BrNum = 3 + 16;
10259  }
10260  else if(TrackElement.SpeedTag == 53)
10261  {
10262  BrNum = 7 + 16;
10263  }
10264  else if(TrackElement.SpeedTag == 56)
10265  {
10266  BrNum = 5 + 16;
10267  }
10268  }
10269  }
10270  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10271  {
10272  GrNum = BrNum;
10273  }
10274  else
10275  {
10276  GrNum = Index;
10277  }
10278  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
10279  {
10280  if(GrNum > 15) // underbridge
10281  {
10282  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
10283  }
10284  else
10285  {
10286  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
10287  }
10288  if(TrackElement.SpeedTag == 64)
10289  {
10290  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10291  }
10292  if(TrackElement.SpeedTag == 65)
10293  {
10295  }
10296  if(TrackElement.SpeedTag == 66)
10297  {
10299  }
10300  if(TrackElement.SpeedTag == 67)
10301  {
10303  }
10304  if(TrackElement.SpeedTag == 80)
10305  {
10306  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
10307  }
10308  if(TrackElement.SpeedTag == 81)
10309  {
10311  }
10312  if(TrackElement.SpeedTag == 82)
10313  {
10315  }
10316  if(TrackElement.SpeedTag == 83)
10317  {
10319  }
10320  if(TrackElement.SpeedTag == 84)
10321  {
10323  }
10324  if(TrackElement.SpeedTag == 85)
10325  {
10327  }
10328  if(TrackElement.SpeedTag == 86)
10329  {
10331  }
10332  if(TrackElement.SpeedTag == 87)
10333  {
10335  }
10336  if(TrackElement.SpeedTag == 129)
10337  {
10338  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10339  }
10340  if(TrackElement.SpeedTag == 130)
10341  {
10343  }
10344  }
10345 
10346  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10347  {
10348  if(GrNum > 15) // underbridge
10349  {
10350  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10351  }
10352  else
10353  {
10354  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10355  }
10356  if(TrackElement.SpeedTag == 64)
10357  {
10358  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10359  }
10360  if(TrackElement.SpeedTag == 65)
10361  {
10362  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10363  }
10364  if(TrackElement.SpeedTag == 66)
10365  {
10366  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10367  }
10368  if(TrackElement.SpeedTag == 67)
10369  {
10370  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10371  }
10372  if(TrackElement.SpeedTag == 80)
10373  {
10374  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10375  }
10376  if(TrackElement.SpeedTag == 81)
10377  {
10378  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10379  }
10380  if(TrackElement.SpeedTag == 82)
10381  {
10382  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10383  }
10384  if(TrackElement.SpeedTag == 83)
10385  {
10386  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10387  }
10388  if(TrackElement.SpeedTag == 84)
10389  {
10390  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10391  }
10392  if(TrackElement.SpeedTag == 85)
10393  {
10394  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10395  }
10396  if(TrackElement.SpeedTag == 86)
10397  {
10398  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10399  }
10400  if(TrackElement.SpeedTag == 87)
10401  {
10402  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10403  }
10404  if(TrackElement.SpeedTag == 129)
10405  {
10406  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10407  }
10408  if(TrackElement.SpeedTag == 130)
10409  {
10410  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10411  }
10412  }
10413 
10414  else // SpeedDifferent only: red - use non sig graphics
10415  {
10416  if(GrNum > 15) // underbridge
10417  {
10418  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10419  }
10420  else
10421  {
10422  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10423  }
10424  if(TrackElement.SpeedTag == 64)
10425  {
10426  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10427  }
10428  if(TrackElement.SpeedTag == 65)
10429  {
10431  }
10432  if(TrackElement.SpeedTag == 66)
10433  {
10435  }
10436  if(TrackElement.SpeedTag == 67)
10437  {
10439  }
10440  if(TrackElement.SpeedTag == 80)
10441  {
10442  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10443  }
10444  if(TrackElement.SpeedTag == 81)
10445  {
10447  }
10448  if(TrackElement.SpeedTag == 82)
10449  {
10451  }
10452  if(TrackElement.SpeedTag == 83)
10453  {
10455  }
10456  if(TrackElement.SpeedTag == 84)
10457  {
10459  }
10460  if(TrackElement.SpeedTag == 85)
10461  {
10463  }
10464  if(TrackElement.SpeedTag == 86)
10465  {
10467  }
10468  if(TrackElement.SpeedTag == 87)
10469  {
10471  }
10472  if(TrackElement.SpeedTag == 129)
10473  {
10474  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10475  }
10476  if(TrackElement.SpeedTag == 130)
10477  {
10479  }
10480  }
10481  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10482  Utilities->CallLogPop(620);
10483 }
10484 
10485 // ---------------------------------------------------------------------------
10486 
10487 bool TTrack::IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10488 /* FirstTrack = LinkPos's 0 & 1
10489  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10490 */
10491 {
10492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementDefaultLengthAndSpeed," + TrackElement.LogTrack(10) + "," +
10493  AnsiString((short)FirstTrack));
10494  LengthDifferent = false;
10495  SpeedDifferent = false;
10496  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10497  {
10498  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10499  {
10500  LengthDifferent = true;
10501  }
10502  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10503  {
10504  SpeedDifferent = true;
10505  }
10506  if(LengthDifferent || SpeedDifferent)
10507  {
10508  Utilities->CallLogPop(625);
10509  return(false);
10510  }
10511  Utilities->CallLogPop(626);
10512  return(true);
10513  }
10514 
10515  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10516  {
10517  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10518  {
10519  LengthDifferent = true;
10520  }
10521  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10522  {
10523  SpeedDifferent = true;
10524  }
10525  if(LengthDifferent || SpeedDifferent)
10526  {
10527  Utilities->CallLogPop(627);
10528  return(false);
10529  }
10530  Utilities->CallLogPop(628);
10531  return(true);
10532  }
10533 
10534  else // any other 1 track element, including platforms being present
10535  {
10536  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10537  {
10538  LengthDifferent = true;
10539  }
10540  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10541  {
10542  SpeedDifferent = true;
10543  }
10544  if(LengthDifferent || SpeedDifferent)
10545  {
10546  Utilities->CallLogPop(629);
10547  return(false);
10548  }
10549  Utilities->CallLogPop(630);
10550  return(true);
10551  }
10552 }
10553 
10554 // ---------------------------------------------------------------------------
10555 
10556 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10557 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10558 {
10559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10560  AnsiString(VLoc));
10561  bool FoundFlag;
10562  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10563 
10564  if(!FoundFlag)
10565  {
10566  Utilities->CallLogPop(633);
10567  return(false);
10568  }
10569  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10570  {
10571  Utilities->CallLogPop(634);
10572  return(true); // only need to check first since if second is a platform the the first must be too
10573  }
10574  else
10575  {
10576  Utilities->CallLogPop(635);
10577  return(false);
10578  }
10579 }
10580 
10581 // ---------------------------------------------------------------------------
10582 
10583 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10584 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10585 {
10586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10587  AnsiString(VLoc));
10588  bool FoundFlag;
10589  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10590 
10591  if(!FoundFlag)
10592  {
10593  Utilities->CallLogPop(636);
10594  return(false);
10595  }
10597  {
10598  Utilities->CallLogPop(637);
10599  return(true); // only need to check first since only one used for NamedNonStationLocations
10600  }
10601  else
10602  {
10603  Utilities->CallLogPop(638);
10604  return(false);
10605  }
10606 }
10607 
10608 // ---------------------------------------------------------------------------
10609 
10610 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10611 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10612  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10613  the front of train stop points for each direction.
10614  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10615  end (unless buffers at one or both ends in which case stop points are the end elements).
10616  Note that for a single element the stop point is the element itself (formula doesn't apply).
10617  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10618  repeating the procedure for every element. At the end all unused values are returned to -1.
10619  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10620 */
10621 {
10622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10623  TTrackElement TempElement, StartElement;
10624  AnsiString TempName;
10625  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10626  bool ForwardSet, ReverseSet;
10627 
10628  for(unsigned int x = 0; x < TrackVector.size(); x++)
10629  {
10630  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10632  }
10633  for(unsigned int x = 0; x < TrackVector.size(); x++)
10634  {
10635  TempElement = TrackElementAt(1380, x);
10636  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10637  {
10638  ForwardSet = false;
10639  ReverseSet = false;
10640  VecPos = x;
10641  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10642  // 2nd condition incl so don't re-examine elements with stop links set to 5
10643  {
10644  TempName = TempElement.ActiveTrackElementName;
10645  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10646  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10647  // an element linked at both ends where both links are also named elements
10648  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10649  {
10650  continue; // looking for an end element so skip this one
10651  }
10652  else // reached one end
10653  {
10654  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10655  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10656  // single named element linked at both ends, can't be continuation as platforms not allowed there
10657  {
10658  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10659  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10660  continue;
10661  }
10662  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10663  // single named buffer element (LinkPos 1 is the non-buffer end)
10664  {
10665  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10666  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10667  continue;
10668  }
10669  else
10670  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10671  // and platforms always on straight (conns 0 & 1) section of points
10672  {
10673  for(int y = 0; y < 2; y++)
10674  {
10675  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10676  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10677  /* TTrackElement Temp1 = TempElement;
10678  ***********New section, compiles but not checked - does bit below need to be else if?
10679  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10680  {
10681  //search along Dir direction until find other end, skip if Dir facing buffer end
10682  int NewDir = Dir;
10683  int NewVecPos;
10684  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10685  {
10686  NewVecPos = Temp1.Conn[NewDir];
10687  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10688  Temp1 = TrackElementAt(601, NewVecPos);
10689  }
10690  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10691  {
10692  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10693  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10694  }
10695  }
10696  ***************
10697  */
10698  // end may be linked at both ends but only one link named, or buffer with linked element named
10699  // if a buffer then the named linkpos has to be 1
10700  // already dealt with all types of single element so at least 2 linked named elements
10701  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10702  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10703  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10704  StartElement = TempElement;
10705  StartVecPos = VecPos; //this stays fixed at start of platform group
10706  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10707  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10708  EntryPos = 1 - Dir;
10709  StartEntryPos = 1 - Dir;
10710  Count = 1;
10711  // work along named elements until find the other end
10712  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10713  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10714  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10715  // all stop link pos's are set to 5
10716  {
10717  VecPos = TempElement.Conn[1 - EntryPos];
10718  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10719  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10720  EntryPos = TempEntryPos;
10721  Count++;
10722  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10723  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10724  }
10725  // here when reached other end, maybe buffers, or last named linked element
10726  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10727  // terminal station, set end elements as stop elements
10728  {
10729  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10730  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10731  continue;
10732  }
10733  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10734  // terminal station, set end elements as stop elements
10735  {
10736  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10737  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10738  continue;
10739  }
10740  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10741  ForwardNumber = ((Count + 1) / 2) + 1;
10742  ReverseNumber = (Count - ForwardNumber) + 1;
10743  Count = 1; // starting value
10744  EntryPos = 1 - Dir;
10745  TempElement = StartElement;
10746  VecPos = StartVecPos;
10747  if(Count == ForwardNumber)
10748  {
10749  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10750  ForwardSet = true;
10751  }
10752  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10753  {
10754  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10755  ReverseSet = true;
10756  }
10757  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10758  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10759  {
10760  VecPos = TempElement.Conn[1 - EntryPos];
10761  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10762  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10763  EntryPos = TempEntryPos;
10764  Count++;
10765  if(Count == ForwardNumber)
10766  {
10767  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10768  ForwardSet = true;
10769  }
10770  if(Count == ReverseNumber)
10771  {
10772  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10773  ReverseSet = true;
10774  }
10775  }
10776  }
10777  }
10778  }
10779  }
10780  }
10781  }
10782  }
10783  for(unsigned int x = 0; x < TrackVector.size(); x++)
10784  {
10785  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10786  {
10788  }
10789  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10790  {
10792  }
10793  }
10794  Utilities->CallLogPop(639);
10795 }
10796 
10797 // ---------------------------------------------------------------------------
10798 
10799 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10800 
10801 {
10802 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10803 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10804 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10805 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10806 
10807 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10808 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10809 */
10810  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10811  TTrackElement TempElement;
10812  AnsiString TempName;
10813  std::list<unsigned int> NameList; //end elements
10814  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10815  for(unsigned int x = 0; x < TrackVector.size(); x++)
10816  {
10817  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10819  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10820  {
10821  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10822  }
10823  }
10824  ContinuationNameList.sort();
10825  ContinuationNameList.unique();
10826 
10827  for(unsigned int x = 0; x < TrackVector.size(); x++)
10828  {
10829  TempElement = TrackElementAt(1598, x);
10830  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10831  {
10832  bool NameIsAContinuation = false;
10833  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10834  {
10835  NameIsAContinuation = true;
10836  }
10837  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10838  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10839  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10840  {
10841  TempName = TempElement.ActiveTrackElementName;
10842  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10843  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10844  // an element linked at both ends of single or main track where both links are also named elements with same name
10845  {
10846  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10847  {
10848  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10849  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10850  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10851  {
10852  continue; //not an end element so skip it
10853  }
10854  else //reached an end on the diverging leg
10855  {
10856  NameList.push_back(x);
10857  }
10858  }
10859  else if(TempElement.TrackType == Crossover)
10860  {
10861  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10862  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10863  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10864  {
10865  continue; //not an end element so skip it
10866  }
10867  else
10868  {
10869  NameList.push_back(x);
10870  }
10871  }
10872  else
10873  {
10874  continue; //not points ot crossover & not an end element so skip
10875  }
10876  }
10877  else // reached one end of single or main track
10878  {
10879  NameList.push_back(x);
10880  }
10881 //NameList now contains all non-station end elements
10882  while(!NameList.empty())
10883  {
10884  unsigned int a = NameList.front();
10885  NameList.pop_front();
10886  TTrackElement &TempElement = TrackElementAt(1605, a);
10887  AnsiString TempName = TempElement.ActiveTrackElementName;
10888  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10889  {
10890  TempElement.StationEntryStopLinkPos1 = 1;
10891  }
10892  else
10893  {
10894  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10895  {
10896  TempElement.StationEntryStopLinkPos1 = 1;
10897  }
10898  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10899  {
10900  TempElement.StationEntryStopLinkPos2 = 0;
10901  }
10902  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10903  {
10904  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10905  {
10906  TempElement.StationEntryStopLinkPos3 = 3;
10907  }
10908  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10909  {
10910  TempElement.StationEntryStopLinkPos4 = 2;
10911  }
10912  }
10913  }
10914  }
10915  }
10916  }
10917  }
10918  Utilities->CallLogPop(2640);
10919 }
10920 
10921 // ---------------------------------------------------------------------------
10922 
10923 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10924 {
10925  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10926  TTrackElement Next;
10927 
10929  while(ReturnNextInactiveTrackElement(1, Next))
10930  {
10931  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10932  {
10933  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10934  // need striped graphics
10935  {
10936  if(Next.SpeedTag == 76)
10937  {
10938  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10939  }
10940  else if(Next.SpeedTag == 77)
10941  {
10942  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10943  }
10944  else if(Next.SpeedTag == 78)
10945  {
10946  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10947  }
10948  else if(Next.SpeedTag == 79)
10949  {
10950  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10951  }
10952  else if(Next.SpeedTag == 96)
10953  {
10954  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10955  }
10956  else if(Next.SpeedTag == 131)
10957  {
10958  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10959  }
10960  }
10961  else
10962  {
10963  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10964  }
10965  }
10966  }
10967 
10968  NextTrackElementPtr = TrackVector.begin();
10969  while(ReturnNextTrackElement(1, Next))
10970  {
10971  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10972  {
10973  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10974  {
10975  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10976  {
10977  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10978  }
10979  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10980  {
10981  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10982  }
10983  }
10984  else
10985  {
10986  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10987  }
10988  }
10989  }
10990  Disp->Update();
10991  Utilities->CallLogPop(640);
10992 }
10993 
10994 // ---------------------------------------------------------------------------
10995 
10996 void TTrack::PlotSmallRedGap(int Caller)
10997 {
10998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
11000  Utilities->CallLogPop(1346);
11001 }
11002 
11003 // ---------------------------------------------------------------------------
11004 
11005 void TTrack::TrackClear(int Caller)
11006 {
11007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
11008  TrackVector.clear();
11009  InactiveTrackVector.clear();
11010  TrackMap.clear();
11012  if(TextHandler->TextVector.size() == 0)
11013  {
11014  Display->DisplayOffsetH = 0;
11015  Display->DisplayOffsetV = 0;
11022  HLocMin = 2000000000;
11023  HLocMax = -2000000000;
11024  VLocMin = 2000000000;
11025  VLocMax = -2000000000;
11026  }
11027  else
11028  {
11029  CalcHLocMinEtc(4);
11030  }
11031  Utilities->CallLogPop(1347);
11032 }
11033 
11034 // ---------------------------------------------------------------------------
11035 
11036 void TTrack::CalcHLocMinEtc(int Caller)
11037 {
11038  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
11039  HLocMin = 2000000000;
11040  VLocMin = 2000000000;
11041  HLocMax = -2000000000;
11042  VLocMax = -2000000000;
11043  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
11044  {
11045  if(TrackElementAt(1385, x).SpeedTag == 0)
11046  {
11047  continue; // skip erase elements or would interfere with Min & Max values
11048  }
11049  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
11050  {
11051  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
11052  }
11053  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
11054  {
11055  HLocMax = TrackElementAt(1389, x).HLoc + 1;
11056  }
11057  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
11058  {
11059  VLocMin = TrackElementAt(1391, x).VLoc - 1;
11060  }
11061  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
11062  {
11063  VLocMax = TrackElementAt(1393, x).VLoc + 1;
11064  }
11065  }
11066  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
11067  {
11068  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
11069  {
11070  continue; // shouldn't be any inactive erase elements but include anyway
11071  }
11072  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
11073  {
11074  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
11075  }
11076  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
11077  {
11078  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
11079  }
11080  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
11081  {
11082  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
11083  }
11084  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
11085  {
11086  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
11087  }
11088  }
11089  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
11090  {
11091 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
11092  will fail as x will exceed the maximum value
11093  if(TextHandler->TextPtrAt(, x)->TextString == "")
11094  {
11095  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
11096  }
11097 */
11098  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
11099  if((TextH / 16) - 1 < HLocMin)
11100  {
11101  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
11102  }
11103  if((TextH / 16) + 1 > HLocMax)
11104  {
11105  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
11106  }
11107  if((TextV / 16) - 1 < VLocMin)
11108  {
11109  VLocMin = (TextV / 16) - 1;
11110  }
11111  if((TextV / 16) + 1 > VLocMax)
11112  {
11113  VLocMax = (TextV / 16) + 1;
11114  }
11115  }
11116  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
11117  {
11118  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
11119  {
11120  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
11121  }
11122  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
11123  {
11124  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
11125  }
11126  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
11127  {
11128  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
11129  }
11130  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
11131  {
11132  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
11133  }
11134  }
11135 
11136  Utilities->CallLogPop(641);
11137 }
11138 
11139 // ---------------------------------------------------------------------------
11140 
11141 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
11142  bool &UserGraphicFoundFlag)
11143 {
11144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
11145  TUserGraphicVector::iterator UserGraphicPtr;
11146 
11147  UserGraphicFoundFlag = false;
11148  if(!UserGraphicVector.empty())
11149  {
11150  int x = UserGraphicVector.size();
11151  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
11152  {
11153  x--;
11154  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
11155  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
11156  {
11157  UserGraphicItem = x;
11158  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
11159  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
11160  UserGraphicFoundFlag = true;
11161  Utilities->CallLogPop(2177);
11162  return;
11163  } // if ....
11164 
11165  } // for UserGraphicPtr...
11166  } // if !UserGraphicVector...
11167 
11168  Utilities->CallLogPop(2197);
11169 }
11170 
11171 // ---------------------------------------------------------------------------
11172 
11174 {
11175  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
11176  TrackElement.LogTrack(11));
11177  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
11178  int SpeedTag = TrackElement.SpeedTag;
11179 
11180  if(SpeedTag < 1)
11181  {
11182  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
11183  }
11184  switch(SpeedTag)
11185  {
11186  case 76: // t platform
11187  GraphicOutput = RailGraphics->gl76Striped;
11188  break;
11189 
11190  case 77: // h platform
11191  GraphicOutput = RailGraphics->bm77Striped;
11192  break;
11193 
11194  case 78: // v platform
11195  GraphicOutput = RailGraphics->bm78Striped;
11196  break;
11197 
11198  case 79: // r platform
11199  GraphicOutput = RailGraphics->gl79Striped;
11200  break;
11201 
11202  case 96: // concourse
11203  GraphicOutput = RailGraphics->ConcourseStriped;
11204  break;
11205 
11206  case 129: // v footbridge
11207  GraphicOutput = RailGraphics->gl129Striped;
11208  break;
11209 
11210  case 130: // h footbridge
11211  GraphicOutput = RailGraphics->gl130Striped;
11212  break;
11213 
11214  case 131: // non-station named loc
11215  GraphicOutput = RailGraphics->bmNameStriped;
11216  break;
11217 
11218  case 145: // v u'pass
11219  GraphicOutput = RailGraphics->gl145Striped;
11220  break;
11221 
11222  case 146: // h u'pass
11223  GraphicOutput = RailGraphics->gl146Striped;
11224  break;
11225 
11226  default:
11227  GraphicOutput = TrackElement.GraphicPtr;
11228  break;
11229  }
11230  Utilities->CallLogPop(642);
11231  return(GraphicOutput);
11232 }
11233 
11234 // ---------------------------------------------------------------------------
11235 
11237 {
11238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
11239  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11240  {
11241 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
11242  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
11243  }
11244  Utilities->CallLogPop(643);
11245  return(TrackVector.at(At));
11246 }
11247 
11248 // ---------------------------------------------------------------------------
11249 
11251 {
11252  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
11253  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
11254  {
11255  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
11256  " in InactiveTrackElementAt");
11257  }
11258  Utilities->CallLogPop(644);
11259  return(InactiveTrackVector.at(At));
11260 }
11261 
11262 // ---------------------------------------------------------------------------
11263 
11264 bool TTrack::BlankElementAt(int Caller, int At) const
11265 {
11266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
11267  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11268  {
11269  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
11270  }
11271  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
11272  {
11273  Utilities->CallLogPop(645);
11274  return(true);
11275  }
11276  else
11277  {
11278  Utilities->CallLogPop(646);
11279  return(false);
11280  }
11281 }
11282 
11283 // ---------------------------------------------------------------------------
11284 
11285 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
11286 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
11287  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
11288  split is required a specific check is made using ThisStationLongEnoughForSplit.
11289  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
11290  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
11291 */
11292 {
11293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
11294  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11295  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
11296  TLocationNameMultiMapIterator SNIterator;
11297  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11298 
11299  if(SNRange.first == SNRange.second)
11300  {
11301  Utilities->CallLogPop(972);
11302  return(false); // should have been caught earlier but include for completeness
11303  }
11304  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11305  {
11306  if(SNIterator->second < 0)
11307  {
11308  continue; // exclude footcrossings
11309  }
11310  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
11311  if(InactiveElement.TrackType == Concourse)
11312  {
11313  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11314  }
11315  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11316  {
11317  continue; // only interested in locations where ActiveTrackElementName may be set
11318  }
11319  THVPair HVPair;
11320  HVPair.first = InactiveElement.HLoc;
11321  HVPair.second = InactiveElement.VLoc;
11322  if(TrackMap.find(HVPair) == TrackMap.end())
11323  {
11324  throw Exception
11325  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
11326  }
11327  int TVPos = TrackMap.find(HVPair)->second;
11328  FirstNamedElement = TrackElementAt(560, TVPos);
11329  // first check linked on both sides, skip the check if not
11330  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11331  {
11332  continue;
11333  }
11334  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11335  // ActiveTrackElementNames are points and excluding trailing connections for points
11336  FirstNamedExitPos = 0;
11337  {
11338  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11339  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11340  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11341  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11342  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11343  {
11344  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11345  {
11346  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11347  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11348  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11349  // success, now check FirstNamedElement link not trailing points & if so all OK
11350  {
11351  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11352  {
11353  Utilities->CallLogPop(1002);
11354  return(true);
11355  }
11356  }
11357  }
11358  }
11359  }
11360  // failed, try link 1
11361  FirstNamedExitPos = 1;
11362  {
11363  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11364  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11365  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11366  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11367  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11368  {
11369  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11370  {
11371  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11372  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11373  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11374  // success, now check FirstNamedElement link not trailing points & if so all OK
11375  {
11376  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11377  {
11378  Utilities->CallLogPop(1003);
11379  return(true);
11380  }
11381  }
11382  }
11383  }
11384  }
11385  }
11386  Utilities->CallLogPop(1004);
11387  return(false);
11388 }
11389 
11390 // ---------------------------------------------------------------------------
11391 
11392 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName) //changed at v2.18.0
11393 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11394  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11395  split is required a specific check is made using ThisLocationLongEnoughForSplit.
11396  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11397  buffers explicitly as it will come out automatically with the logic applied.
11398  Note that these conditions exclude opposed buffers since these not linked.
11399 */
11400 {
11401  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11402  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11403  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11404  TLocationNameMultiMapIterator SNIterator;
11405  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11406 
11407  if(SNRange.first == SNRange.second)
11408  {
11409  Utilities->CallLogPop(2641);
11410  return(false); // should have been caught earlier but include for completeness
11411  }
11412  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11413  {
11414  if(SNIterator->second < 0) //negative numbers represent active track elements
11415  {
11416  continue; // exclude footcrossings - only these have active track element names
11417  }
11418  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11419  if(InactiveElement.TrackType == Concourse)
11420  {
11421  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11422  }
11423  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11424  {
11425  continue; // only interested in locations where ActiveTrackElementName may be set
11426  }
11427  THVPair HVPair;
11428  HVPair.first = InactiveElement.HLoc;
11429  HVPair.second = InactiveElement.VLoc;
11430  if(TrackMap.find(HVPair) == TrackMap.end())
11431  {
11432  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11433  }
11434  int TVPos = TrackMap.find(HVPair)->second;
11435  FirstNamedElement = TrackElementAt(1610, TVPos);
11436  // first check linked on both sides, skip the check if not
11437  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11438  {
11439  continue;
11440  }
11441  // check if another ActiveTrackElementName connected via a link
11442  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11443  {
11444  FirstNamedExitPos = 0; //this is the end linked to the second named element
11445  {
11446  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11447  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11448  {
11449  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11450  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11451  {
11452  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11453  }
11454  else if(SecondNamedEntryPos == 2)
11455  {
11456  SecondNamedExitPos = 3;
11457  }
11458  else if(SecondNamedEntryPos == 3)
11459  {
11460  SecondNamedExitPos = 2;
11461  }
11462  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11463  {
11464  Utilities->CallLogPop(2642);
11465  return(true);
11466  } //if not try other exitpos
11467  }
11468  }
11469  FirstNamedExitPos = 1;
11470  {
11471  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11472  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11473  {
11474  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11475  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11476  {
11477  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11478  }
11479  else if(SecondNamedEntryPos == 2)
11480  {
11481  SecondNamedExitPos = 3;
11482  }
11483  else if(SecondNamedEntryPos == 3)
11484  {
11485  SecondNamedExitPos = 2;
11486  }
11487  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11488  {
11489  Utilities->CallLogPop(2643);
11490  return(true);
11491  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11492  }
11493  }
11494  }
11495  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11496  {
11497  FirstNamedExitPos = 2;
11498  {
11499  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11500  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11501  {
11502  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11503  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11504  {
11505  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11506  }
11507  else if(SecondNamedEntryPos == 2)
11508  {
11509  SecondNamedExitPos = 3;
11510  }
11511  else if(SecondNamedEntryPos == 3)
11512  {
11513  SecondNamedExitPos = 2;
11514  }
11515  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11516  {
11517  Utilities->CallLogPop(2644);
11518  return(true);
11519  } //if not try other exitpos
11520  }
11521  }
11522  FirstNamedExitPos = 3;
11523  {
11524  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11525  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11526  {
11527  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11528  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11529  {
11530  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11531  }
11532  else if(SecondNamedEntryPos == 2)
11533  {
11534  SecondNamedExitPos = 3;
11535  }
11536  else if(SecondNamedEntryPos == 3)
11537  {
11538  SecondNamedExitPos = 2;
11539  }
11540  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11541  {
11542  Utilities->CallLogPop(2645);
11543  return(true);
11544  } //failed so continue to next element or return false
11545  }
11546  }
11547  }
11548  }
11549  Utilities->CallLogPop(2646);
11550  return(false);
11551 }
11552 
11553 // ---------------------------------------------------------------------------
11554 
11555 //new version at v2.18.0
11556 bool TTrack::ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement,
11557  int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
11558 /* Return false if the track that the train is on isn't long enough for a split - only 1 named element or 2 with only one external link.
11559 Otherwise find the best 4 final element positions, preferably with FrontTrainFrontPos on a named element. Conditions are that the original train
11560 will lie within the 4 elements of the two split trains, and at least 1 element of each split train will be at the location. Within those conditions
11561 the lead element of the front train will be at the location if it is possible.
11562 */
11563 {
11564  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisLocationLongEnoughForSplit," + AnsiString(TrainID) + "," +
11565  LocationName + AnsiString(LeadElement) + "," + AnsiString(LeadExitPos) + "," + AnsiString(MidElement) + "," + AnsiString(MidEntryPos));
11566 
11567  TemporaryDelay = false; //used in calling function to set LastActionTime to TTClockTime so failure messages only given every 30 secs
11568  //count forwards from LeadElement - only need to count forwards 2 elements to ptovide for room for new front train
11569  int FwdPos[3] = {LeadElement, -1, -1}; //0 starts at LeadElement and increases as go forwards
11570  int RwdPos[3] = {MidElement, -1, -1}; //0 starts at MidElement and increases as go backwards
11571  TTrackElement FwdPos0Element = TrackElementAt(1666, LeadElement);
11572  TTrackElement RwdPos0Element = TrackElementAt(1667, MidElement);
11573  int FwdPos1EntryPos, FwdPos1ExitPos, FwdPos2EntryPos, FwdPos2ExitPos, RwdPos1EntryPos, RwdPos1ExitPos, RwdPos2EntryPos, RwdPos2ExitPos; //these needed to test for other train on element
11574 
11575  bool FwdDerail1 = false, FwdDerail2 = false, RwdDerail1 = false, RwdDerail2 = false;
11576  int NumFwdNamedElements = 0, NumFwdElements = 0, NumRwdNamedElements = 0, NumRwdElements = 1; //Fwd = ahead of LeadElement, Rwd includes MidElement
11577  if(RwdPos0Element.ActiveTrackElementName == LocationName) //MidElement
11578  {
11579  NumRwdNamedElements = 1;
11580  }
11581 
11582  FwdPos[1] = FwdPos0Element.Conn[LeadExitPos];
11583  if(FwdPos[1] > -1)
11584  {
11585  NumFwdElements = 1;
11586  TTrackElement FwdPos1Element = TrackElementAt(1668, FwdPos[1]);
11587  if(FwdPos1Element.ActiveTrackElementName == LocationName)
11588  {
11589  NumFwdNamedElements = 1;
11590  }
11591  FwdPos1EntryPos = FwdPos0Element.ConnLinkPos[LeadExitPos];
11592  FwdPos1ExitPos = GetAnyElementOppositeLinkPos(4, FwdPos[1], FwdPos1EntryPos, FwdDerail1);
11593  FwdPos[2] = FwdPos1Element.Conn[FwdPos1ExitPos];
11594  if(FwdPos[2] > -1)
11595  {
11596  NumFwdElements = 2;
11597  FwdPos2EntryPos = FwdPos1Element.ConnLinkPos[FwdPos1ExitPos];
11598  FwdPos2ExitPos = GetAnyElementOppositeLinkPos(5, FwdPos[2], FwdPos2EntryPos, FwdDerail2); //this is purely to obtain Derail
11599  TTrackElement FwdPos2Element = TrackElementAt(1669, FwdPos[2]);
11600  if(FwdPos2Element.ActiveTrackElementName == LocationName)
11601  {
11602  NumFwdNamedElements = 2;
11603  }
11604  }
11605  }
11606 //this is as far as need to go forwards
11607 
11608  RwdPos[1] = RwdPos0Element.Conn[MidEntryPos];
11609  if(RwdPos[1] > -1)
11610  {
11611  NumRwdElements = 2; //includes MidElement
11612  TTrackElement RwdPos1Element = TrackElementAt(1670, RwdPos[1]);
11613  if(RwdPos1Element.ActiveTrackElementName == LocationName)
11614  {
11615  NumRwdNamedElements = 2; //includes MidElement (treats MidElement as named even if not, as eventual positions will be same either way)
11616  }
11617  RwdPos1ExitPos = RwdPos0Element.ConnLinkPos[MidEntryPos];
11618  RwdPos1EntryPos = GetAnyElementOppositeLinkPos(6, RwdPos[1], RwdPos1ExitPos, RwdDerail1);
11619  RwdPos[2] = RwdPos1Element.Conn[RwdPos1EntryPos];
11620  if(RwdPos[2] > -1)
11621  {
11622  NumRwdElements = 3; //includes MidElement
11623  RwdPos2ExitPos = RwdPos1Element.ConnLinkPos[RwdPos1EntryPos];
11624  RwdPos2EntryPos = GetAnyElementOppositeLinkPos(7, RwdPos[2], RwdPos2ExitPos, RwdDerail2); //this is purely to obtain Derail
11625  TTrackElement RwdPos2Element = TrackElementAt(1671, RwdPos[2]);
11626  if(RwdPos2Element.ActiveTrackElementName == LocationName)
11627  {
11628  NumRwdNamedElements = 3; //includes MidElement (treats MidElement & next position to rear as both named even if not, as eventual positions will be same either way)
11629  }
11630  }
11631  }
11632 //this is as far as need to go backwards
11633 
11634 //now try to accommodate front train on named elements if possible
11635  if(NumFwdNamedElements == 2)//Front train moves onto the 2 forward named elements & rear train is on original train elements X N N N (N = named, X = named or not)
11636  { // M L - - >> RM RL FM FL
11637  FrontTrainFrontPos = FwdPos[2];
11638  FrontTrainRearPos = FwdPos[1];
11639  RearTrainFrontPos = LeadElement;
11640  RearTrainRearPos = MidElement;
11641  if(FwdDerail1 || FwdDerail2)
11642  {
11643  TrainController->StopTTClockMessage(159, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11644  TemporaryDelay = true;
11645  Utilities->CallLogPop(2661); //may be able to split further back but leave as is to avoid complication
11646  return(true);
11647  }
11648  if(OtherTrainOnTrack(6, FwdPos[1], FwdPos1EntryPos, TrainID))
11649  {
11650  TrainController->StopTTClockMessage(160, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11651  TemporaryDelay = true;
11652  Utilities->CallLogPop(2662); //may be able to split further back but leave as is to avoid complication
11653  return(true);
11654  }
11655  if(OtherTrainOnTrack(7, FwdPos[2], FwdPos2ExitPos, TrainID))
11656  {
11657  TrainController->StopTTClockMessage(161, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11658  TemporaryDelay = true;
11659  Utilities->CallLogPop(2663); //may be able to split further back but leave as is to avoid complication
11660  return(true);
11661  }
11662  Utilities->CallLogPop(2664);
11663  return(true);
11664  }
11665 
11666  else if((NumFwdNamedElements == 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11667  { //Front train moves onto the 1 forward named element & rear train occupies 1 element behind original train - M L - >> RM RL FM FL
11668  FrontTrainFrontPos = FwdPos[1];
11669  FrontTrainRearPos = LeadElement;
11670  RearTrainFrontPos = MidElement;
11671  RearTrainRearPos = RwdPos[1];
11672  if(FwdDerail1)
11673  {
11674  TrainController->StopTTClockMessage(162, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11675  TemporaryDelay = true;
11676  Utilities->CallLogPop(2665); //may be able to split further back but leave as is to avoid complication
11677  return(true);
11678  }
11679  if(RwdDerail1)
11680  {
11681  TrainController->StopTTClockMessage(163, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11682  TemporaryDelay = true;
11683  Utilities->CallLogPop(2666); //may be able to split further back but leave as is to avoid complication
11684  return(true);
11685  }
11686  if(OtherTrainOnTrack(8, FwdPos[1], FwdPos1EntryPos, TrainID))
11687  {
11688  TrainController->StopTTClockMessage(164, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11689  TemporaryDelay = true;
11690  Utilities->CallLogPop(2667); //may be able to split further back but leave as is to avoid complication
11691  return(true);
11692  }
11693  if(OtherTrainOnTrack(9, RwdPos[1], RwdPos1ExitPos, TrainID))
11694  {
11695  TrainController->StopTTClockMessage(165, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11696  TemporaryDelay = true;
11697  Utilities->CallLogPop(2668); //may be able to split further back but leave as is to avoid complication
11698  return(true);
11699  }
11700  Utilities->CallLogPop(2669);
11701  return(true);
11702  }
11703 
11704  else if((NumRwdNamedElements >= 2) && (NumRwdElements == 3)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11705  {//front train occupies original train position and rear train fits behind it - - M L >> RM RL FM FL
11706  FrontTrainFrontPos = LeadElement;
11707  FrontTrainRearPos = MidElement;
11708  RearTrainFrontPos = RwdPos[1];
11709  RearTrainRearPos = RwdPos[2];
11710  if(RwdDerail1 || RwdDerail2)
11711  {
11712  TrainController->StopTTClockMessage(166, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11713  TemporaryDelay = true;
11714  Utilities->CallLogPop(2670); //may be able to split further back but leave as is to avoid complication
11715  return(true);
11716  }
11717  if(OtherTrainOnTrack(10, RwdPos[1], RwdPos1ExitPos, TrainID))
11718  {
11719  TrainController->StopTTClockMessage(167, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11720  TemporaryDelay = true;
11721  Utilities->CallLogPop(2671); //may be able to split further back but leave as is to avoid complication
11722  return(true);
11723  }
11724  if(OtherTrainOnTrack(11, RwdPos[2], RwdPos2EntryPos, TrainID))
11725  {
11726  TrainController->StopTTClockMessage(168, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11727  TemporaryDelay = true;
11728  Utilities->CallLogPop(2672); //may be able to split further back but leave as is to avoid complication
11729  return(true);
11730  }
11731  Utilities->CallLogPop(2673);
11732  return(true);
11733  }
11734 
11735 //here look for front overhang situations
11736  else if((NumFwdNamedElements == 1) && (NumFwdElements == 2)) // X N N X (N = named, X = named or not but connected)
11737  { // M L - - >> RM RL FM FL
11738  FrontTrainFrontPos = FwdPos[2];
11739  FrontTrainRearPos = FwdPos[1];
11740  RearTrainFrontPos = LeadElement;
11741  RearTrainRearPos = MidElement;
11742  if(FwdDerail1 || FwdDerail2)
11743  {
11744  TrainController->StopTTClockMessage(169, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11745  TemporaryDelay = true;
11746  Utilities->CallLogPop(2674); //may be able to split further back but leave as is to avoid complication
11747  return(true);
11748  }
11749  if(OtherTrainOnTrack(12, FwdPos[1], FwdPos1EntryPos, TrainID))
11750  {
11751  TrainController->StopTTClockMessage(170, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11752  TemporaryDelay = true;
11753  Utilities->CallLogPop(2675); //may be able to split further back but leave as is to avoid complication
11754  return(true);
11755  }
11756  if(OtherTrainOnTrack(13, FwdPos[2], FwdPos2ExitPos, TrainID))
11757  {
11758  TrainController->StopTTClockMessage(171, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11759  TemporaryDelay = true;
11760  Utilities->CallLogPop(2676); //may be able to split further back but leave as is to avoid complication
11761  return(true);
11762  }
11763  Utilities->CallLogPop(2677);
11764  return(true);
11765  }
11766 
11767  else if((NumFwdElements >= 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) // X N N X (N = named, X = named or not but connected)
11768  { // - M L - >> RM RL FM FL
11769  FrontTrainFrontPos = FwdPos[1];
11770  FrontTrainRearPos = LeadElement;
11771  RearTrainFrontPos = MidElement;
11772  RearTrainRearPos = RwdPos[1];
11773  if(FwdDerail1)
11774  {
11775  TrainController->StopTTClockMessage(172, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11776  TemporaryDelay = true;
11777  Utilities->CallLogPop(2678); //may be able to split further back but leave as is to avoid complication
11778  return(true);
11779  }
11780  if(RwdDerail1)
11781  {
11782  TrainController->StopTTClockMessage(173, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11783  TemporaryDelay = true;
11784  Utilities->CallLogPop(2679); //may be able to split further back but leave as is to avoid complication
11785  return(true);
11786  }
11787  if(OtherTrainOnTrack(14, FwdPos[1], FwdPos1EntryPos, TrainID))
11788  {
11789  TrainController->StopTTClockMessage(174, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11790  TemporaryDelay = true;
11791  Utilities->CallLogPop(2680); //may be able to split further back but leave as is to avoid complication
11792  return(true);
11793  }
11794  if(OtherTrainOnTrack(15, RwdPos[1], RwdPos1ExitPos, TrainID))
11795  {
11796  TrainController->StopTTClockMessage(175, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11797  TemporaryDelay = true;
11798  Utilities->CallLogPop(2681); //may be able to split further back but leave as is to avoid complication
11799  return(true);
11800  }
11801  Utilities->CallLogPop(2682);
11802  return(true);
11803  }
11804 //anything else fails as location too short
11805  Utilities->CallLogPop(2652);
11806  return(false);
11807 }
11808 
11809 // ---------------------------------------------------------------------------
11810 
11811 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11812 {
11813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11814  TLocationNameMultiMapIterator SNIterator;
11815  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11816 
11817  if(SNRange.first != SNRange.second)
11818  {
11819  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11820  {
11821  if(SNIterator->second < 0)
11822  {
11823  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11824  }
11825  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11826  SNIterator->second).TrackType == NamedNonStationLocation))
11827  {
11828  Utilities->CallLogPop(1121);
11829  return(true);
11830  }
11831  }
11832  }
11833  Utilities->CallLogPop(848);
11834  return(false);
11835 }
11836 
11837 // ---------------------------------------------------------------------------
11838 
11839 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11840 {
11841 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11842  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11843  "," + AnsiString(SpeedTag));
11844  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11845  {
11846  Utilities->CallLogPop(949);
11847  return(false);
11848  }
11849  bool FoundFlag;
11850  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11851 
11852  if(!FoundFlag)
11853  {
11854  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11855  }
11856  TTrackElement IAElement;
11857 
11858  if(SpeedTag == 68) // top sig
11859  {
11860  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11861  {
11862  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11863  {
11864  IAElement = InactiveTrackElementAt(50, IMPair.first);
11865  }
11866  else
11867  {
11868  IAElement = InactiveTrackElementAt(51, IMPair.second);
11869  }
11870  if(IAElement.LocationName == "")
11871  {
11872 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11873  SignalPlatformGraphic = RailGraphics->gl76Striped;
11874  }
11875  else
11876  {
11877 // SignalPlatformGraphic = RailGraphics->Plat68;
11878  SignalPlatformGraphic = RailGraphics->gl76;
11879  }
11880  Utilities->CallLogPop(950);
11881  return(true);
11882  }
11883  }
11884  else if(SpeedTag == 69) // bot sig
11885  {
11886  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11887  {
11888  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11889  {
11890  IAElement = InactiveTrackElementAt(77, IMPair.first);
11891  }
11892  else
11893  {
11894  IAElement = InactiveTrackElementAt(78, IMPair.second);
11895  }
11896  if(IAElement.LocationName == "")
11897  {
11898 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11899  SignalPlatformGraphic = RailGraphics->bm77Striped;
11900  }
11901  else
11902  {
11903 // SignalPlatformGraphic = RailGraphics->Plat69;
11904  SignalPlatformGraphic = RailGraphics->bm77;
11905  }
11906  Utilities->CallLogPop(951);
11907  return(true);
11908  }
11909  }
11910  else if(SpeedTag == 70) // left sig
11911  {
11912  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11913  {
11914  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11915  {
11916  IAElement = InactiveTrackElementAt(55, IMPair.first);
11917  }
11918  else
11919  {
11920  IAElement = InactiveTrackElementAt(82, IMPair.second);
11921  }
11922  if(IAElement.LocationName == "")
11923  {
11924 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11925  SignalPlatformGraphic = RailGraphics->bm78Striped;
11926  }
11927  else
11928  {
11929 // SignalPlatformGraphic = RailGraphics->Plat70;
11930  SignalPlatformGraphic = RailGraphics->bm78;
11931  }
11932  Utilities->CallLogPop(952);
11933  return(true);
11934  }
11935  }
11936  else if(SpeedTag == 71) // right sig
11937  {
11938  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11939  {
11940  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11941  {
11942  IAElement = InactiveTrackElementAt(85, IMPair.first);
11943  }
11944  else
11945  {
11946  IAElement = InactiveTrackElementAt(86, IMPair.second);
11947  }
11948  if(IAElement.LocationName == "")
11949  {
11950 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11951  SignalPlatformGraphic = RailGraphics->gl79Striped;
11952  }
11953  else
11954  {
11955 // SignalPlatformGraphic = RailGraphics->Plat71;
11956  SignalPlatformGraphic = RailGraphics->gl79;
11957  }
11958  Utilities->CallLogPop(953);
11959  return(true);
11960  }
11961  }
11962  Utilities->CallLogPop(954);
11963  return(false);
11964 }
11965 
11966 // ---------------------------------------------------------------------------
11967 
11968 bool TTrack::OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
11969 // returns true if another train on LinkPos track of element at TrackPos, whether bridge or not, return false if not, or if TrackPos == -1,
11970 // or LinkPos == -1, or if only own train on the track. LinkPos can be entry or exit.
11971 {
11972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(TrackPos) + "," +
11973  AnsiString(LinkPos) + "," + AnsiString(OwnTrainID));
11974  if((LinkPos < 0) || (TrackPos < 0))
11975  {
11976  Utilities->CallLogPop(1348);
11977  return(false);
11978  }
11979  TTrackElement TrackElement = TrackElementAt(713, TrackPos);
11980 
11981  if(TrackElement.TrackType != Bridge)
11982  {
11983  Utilities->CallLogPop(1349);
11984  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11985  }
11986 // bridge if reach here
11987  if(LinkPos > 1)
11988  {
11989  Utilities->CallLogPop(1350);
11990  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11991  }
11992  else
11993  {
11994  Utilities->CallLogPop(1351);
11995  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11996  }
11997 }
11998 
11999 // ---------------------------------------------------------------------------
12000 
12002 {
12003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
12004  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
12005  {
12006  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
12007  }
12008  Utilities->CallLogPop(1483);
12009  return(SelectVector.at(At));
12010 }
12011 
12012 // ---------------------------------------------------------------------------
12013 
12014 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
12015 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
12016 {
12017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
12018  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
12019  bool FoundFlag = false;
12020  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
12021  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
12022 
12023  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
12024  Utilities->CallLogPop(1538);
12025  return(FoundFlag);
12026 }
12027 
12028 // ---------------------------------------------------------------------------
12029 
12030 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
12031 {
12032 // return true if find an inactive element called 'Name'
12033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
12034  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
12035  bool FoundFlag = false;
12036 
12037  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12038  {
12039  if(InactiveTrackElementAt(158, x).LocationName == Name)
12040  {
12041  FoundFlag = true;
12042  int V = InactiveTrackElementAt(159, x).VLoc;
12043  int H = InactiveTrackElementAt(160, x).HLoc;
12044  if(V > VLocHi)
12045  {
12046  VLocHi = V;
12047  }
12048  if(V < VLocLo)
12049  {
12050  VLocLo = V;
12051  }
12052  if(H < HLoc)
12053  {
12054  HLoc = H;
12055  }
12056  }
12057  }
12058  if(FoundFlag)
12059  {
12060  VPosHi = 16 * VLocHi;
12061  VPosLo = 16 * VLocLo;
12062  HPos = 16 * HLoc;
12063  Utilities->CallLogPop(1562);
12064  return(true);
12065  }
12066  else
12067  {
12068  Utilities->CallLogPop(1563);
12069  return(false);
12070  }
12071 }
12072 
12073 // ---------------------------------------------------------------------------
12074 
12075 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
12076 {
12077 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
12078 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
12079  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
12080  AnsiString(EndTVPosition));
12081  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
12082  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
12083 
12084 // get H & V values for the element adjacent to Link[0] & Link[1]
12085  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
12086  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
12087  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
12088  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
12089 
12090 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
12091  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
12092  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
12093  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
12094  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
12095 
12096  if(Link0Squares <= Link1Squares)
12097  {
12098  Utilities->CallLogPop(1851);
12099  return(0);
12100  }
12101  else
12102  {
12103  Utilities->CallLogPop(1852);
12104  return(1);
12105  }
12106 }
12107 
12108 // ---------------------------------------------------------------------------
12109 
12110 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
12111 {
12112  // element can be points or any other type
12113  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
12114  AnsiString(LinkPos));
12115  Derail = false;
12116  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
12117 
12118  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
12119  {
12120  if(TE.Attribute == 0)
12121  {
12122  Utilities->CallLogPop(663);
12123  return(1); // Att == 0 & ExitPos == 1 represent straight
12124  }
12125  else
12126  {
12127  Utilities->CallLogPop(664);
12128  return(3); // Att == 1 & ExitPos == 3 represent diverging
12129  }
12130  }
12131  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
12132  {
12133  if((LinkPos == 1) && (TE.Attribute == 0))
12134  {
12135  Utilities->CallLogPop(665);
12136  return(0); // Att == 0 represents straight
12137  }
12138  else if(LinkPos == 1)
12139  {
12140  Derail = true;
12141  Utilities->CallLogPop(666);
12142  return(0);
12143  }
12144  else if((LinkPos == 3) && (TE.Attribute == 1))
12145  {
12146  Utilities->CallLogPop(667);
12147  return(0);
12148  }
12149  else if(LinkPos == 3)
12150  {
12151  Derail = true;
12152  Utilities->CallLogPop(668);
12153  return(0);
12154  }
12155  }
12156  else if(LinkPos == 0)
12157  {
12158  Utilities->CallLogPop(669);
12159  return(1);
12160  }
12161  else if(LinkPos == 1)
12162  {
12163  Utilities->CallLogPop(670);
12164  return(0);
12165  }
12166  else if(LinkPos == 2)
12167  {
12168  Utilities->CallLogPop(671);
12169  return(3);
12170  }
12171  else if(LinkPos == 3)
12172  {
12173  Utilities->CallLogPop(672);
12174  return(2);
12175  }
12176  throw Exception("Error, failure in GetExitPos"); // should never reach here
12177 }
12178 
12179 // ----------------------------------------------------------------------------
12180 
12182 {
12183  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
12184  LCVector.clear();
12185  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12186  {
12187  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
12188  {
12189  LCVector.push_back(x);
12190  }
12191  }
12192  Utilities->CallLogPop(1931);
12193  return;
12194 }
12195 
12196 // ---------------------------------------------------------------------------
12197 
12198 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
12199 /*
12200  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
12201  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
12202  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
12203  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
12204 */
12205 {
12206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
12207  AnsiString(Link));
12208  bool FoundFlag;
12209 
12210  TrainID = -1;
12211  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
12212 
12213  if(!FoundFlag)
12214  {
12215  Utilities->CallLogPop(2001);
12216  return(false);
12217  }
12218  TTrackElement TE = TrackElementAt(882, VecPos);
12219 
12220  TrainID = TE.TrainIDOnElement;
12221  if(TE.TrackType == Bridge)
12222  {
12223  if(TE.TrainIDOnElement > -1)
12224  {
12225  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
12226  {
12228  }
12229  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
12230  {
12232  }
12233  else
12234  {
12235  TrainID = -1; // shouldn't ever reach here but be safe
12236  }
12237  }
12238  }
12239  if(TrainID == -1)
12240  {
12241  Utilities->CallLogPop(2002);
12242  return(false);
12243  }
12244 // now get the train
12245  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
12246 
12247  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
12248  {
12249  Utilities->CallLogPop(2003);
12250  return(true);
12251  }
12252  TrainID = -1;
12253  Utilities->CallLogPop(2004);
12254  return(false);
12255 }
12256 
12257 // ---------------------------------------------------------------------------
12258 
12259 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
12260 /* New at v1.2.0
12261  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
12262  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
12263  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12264  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12265  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12266  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12267  Each of these is examined in turn for each route element in the relevant position.
12268 */
12269 {
12270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
12271  "," + AnsiString(DiagonalLinkNumber));
12272  TrainID = -1;
12273  TPrefDirElement TempPrefDirElement;
12274  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
12275 
12276  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
12277  {
12278  Utilities->CallLogPop(2027);
12279  return(true);
12280  }
12281  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
12282  {
12283  Utilities->CallLogPop(2028);
12284  return(true);
12285  }
12286  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
12287  {
12288  Utilities->CallLogPop(2029);
12289  return(true);
12290  }
12291  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
12292  {
12293  Utilities->CallLogPop(2030);
12294  return(true);
12295  }
12296  Utilities->CallLogPop(2031);
12297  return(false);
12298 }
12299 
12300 // ---------------------------------------------------------------------------
12301 
12302 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12303 {
12304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12305  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12306  TUserGraphicItem UGI;
12307  AnsiString JustFileName = "";
12308 
12309  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12310  {
12311  UGI = UserGraphicVectorAt(17, x);
12312  int LastDelim = UGI.FileName.LastDelimiter('\\');
12313  if(LastDelim == 0) // can't find it so skip this item
12314  {
12315  continue;
12316  }
12317  else
12318  {
12319  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12320  }
12321  Utilities->SaveFileString(VecFile, JustFileName);
12322  Utilities->SaveFileInt(VecFile, UGI.HPos);
12323  Utilities->SaveFileInt(VecFile, UGI.VPos);
12324  }
12325  Utilities->CallLogPop(2178);
12326 }
12327 
12328 // ---------------------------------------------------------------------------
12329 
12330 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12331 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12332 {
12333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12334  int NumPlats = 0;
12335  TTrackElement TempElement;
12336  int TempInt;
12337 
12338  typedef std::list<int> TNamePosList;
12339  TNamePosList NamePosList;
12340  typedef TNamePosList::iterator TNPLIt;
12341  TNPLIt NPLIt;
12342  typedef std::list<int> TOnePlatList;
12343  TOnePlatList OnePlatList;
12344  typedef TOnePlatList::iterator TOPLIt;
12345  TOPLIt OPLIt;
12346 
12347  NamePosList.clear();
12348  OnePlatList.clear();
12349  for(unsigned int x = 0; x < TrackVector.size(); x++)
12350  {
12351  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12352  {
12353  NamePosList.push_back(x);
12354  }
12355  }
12356  //NamePosList complete
12357 
12358  if(!NamePosList.empty()) //first value for the loop examination
12359  {
12360  OnePlatList.push_back(NamePosList.back());
12361  NamePosList.pop_back(); //erase from NPV as done with it here
12362  }
12363  while(!OnePlatList.empty()) //loop to examine all linked elements
12364  {
12365  TempInt = OnePlatList.front();
12366  TempElement = TrackElementAt(989, TempInt);
12367 
12368  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12369  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12370  {
12371  OnePlatList.push_back(TempElement.Conn[0]);
12372  NamePosList.erase(NPLIt);
12373  }
12374  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12375  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12376  {
12377  OnePlatList.push_back(TempElement.Conn[1]);
12378  NamePosList.erase(NPLIt);
12379  }
12380  //here when loaded any connecting links into OnePlatList, so can erase the front element
12381  OnePlatList.erase(OnePlatList.begin());
12382  if(OnePlatList.empty())
12383  {
12384  NumPlats++; //finished with current linked elements so can increment NumPlats
12385  if(!NamePosList.empty())
12386  {
12387  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12388  NamePosList.pop_back(); //erase from NPV as done with it there
12389  }
12390  }
12391  }
12392  Utilities->CallLogPop(2218);
12393  return(NumPlats);
12394 }
12395 
12396 // ---------------------------------------------------------------------------
12397 
12398 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12399 {//repair Signals pointed to by FPVIt
12400  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12401  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12402  if(TE.TrackType != SignalPost)
12403  {
12404  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12405  }
12406  if(!TE.Failed)
12407  {
12408  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12409  }
12410  TE.Failed = false;
12411  //set to correct aspect
12412  int RouteNumber;
12413  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12414  { // 0 for LinkPos ok as a signal so only one track
12415  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12416  }
12417  //erase from vector
12418  Track->FailedSignalsVector.erase(FPVIt);
12419 
12420  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12421  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12422  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12423  AllRoutes->RebuildRailwayFlag = true;
12424  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12425  Utilities->CallLogPop(2519);
12426 }
12427 
12428 // ---------------------------------------------------------------------------
12429 
12430 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12431 {//repair points pointed to by FPVIt
12432  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12433  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12434  if(TE.TrackType != Points)
12435  {
12436  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12437  }
12438  if(!TE.Failed)
12439  {
12440  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12441  }
12442  TE.Failed = false;
12447  //erase from vector
12448  Track->FailedPointsVector.erase(FPVIt);
12449 
12450  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12451  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12452  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12453  AllRoutes->RebuildRailwayFlag = true;
12454  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12455  Utilities->CallLogPop(2518);
12456 }
12457 
12458 // ---------------------------------------------------------------------------
12459 
12460 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12461 {//repair TSR pointed to by FPVIt
12462  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12463  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12464  if(TE.TrackType != Simple)
12465  {
12466  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12467  }
12468  if(!TE.Failed)
12469  {
12470  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12471  }
12472  TE.Failed = false;
12475  //erase from vector
12476  Track->TSRVector.erase(FPVIt);
12477 
12478  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12479  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12480  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12481  AllRoutes->RebuildRailwayFlag = true;
12482  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12483  Utilities->CallLogPop(2520);
12484 }
12485 
12486 // ---------------------------------------------------------------------------
12487 
12489 {
12490  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12491  SimpleVector.clear();
12492  for(unsigned int x = 0; x < TrackVector.size(); x++)
12493  {
12494  if(TrackElementAt(1517, x).TrackType == Simple)
12495  {
12496  SimpleVector.push_back(int(x));
12497  }
12498  }
12499  Utilities->CallLogPop(2521);
12500 }
12501 
12502 // ---------------------------------------------------------------------------
12503 // UserGraphic, PrefDir & Route functions
12504 // ---------------------------------------------------------------------------
12505 
12507 {
12508  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12509  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12510  {
12511  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12512  }
12513  Utilities->CallLogPop(2194);
12514  return(UserGraphicVector.at(At));
12515 }
12516 
12517 // ---------------------------------------------------------------------------
12518 
12519 int TOnePrefDir::LastElementNumber(int Caller) const
12520 {
12521  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12522  int RetVal = PrefDirVector.size() - 1;
12523 
12524  if(RetVal < 0)
12525  {
12526  throw Exception("Return value negative in call to LastElementNumber");
12527  }
12528  Utilities->CallLogPop(114);
12529  return(RetVal);
12530 }
12531 
12532 // ---------------------------------------------------------------------------
12534 {
12535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12536  if(PrefDirVector.empty())
12537  {
12538  throw Exception("PrefDirVector empty in call to LastElementPtr");
12539  }
12540  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12541 
12542  Utilities->CallLogPop(115);
12543  return(RetIT);
12544 }
12545 
12546 // ---------------------------------------------------------------------------
12548 {
12549  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12550  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12551  {
12552  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12553  }
12554  Utilities->CallLogPop(116);
12555  return(PrefDirVector.at(At));
12556 }
12557 
12558 // ---------------------------------------------------------------------------
12560 {
12561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12562  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12563  {
12564  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12565  " in GetModifiablePrefDirElementAt");
12566  }
12567  Utilities->CallLogPop(117);
12568  return(PrefDirVector.at(At));
12569 }
12570 
12571 // ---------------------------------------------------------------------------
12573 {
12574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12575  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12576  {
12577  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12578  }
12579  Utilities->CallLogPop(118);
12580  return(SearchVector.at(At));
12581 }
12582 
12583 // ---------------------------------------------------------------------------
12585 {
12586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12587  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12588  {
12589  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12590  }
12591  Utilities->CallLogPop(119);
12592  return(SearchVector.at(At));
12593 }
12594 
12595 // ---------------------------------------------------------------------------
12596 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12597 /*
12598  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12599  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12600  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12601  set in later functions.
12602 */
12603 {
12604  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12605  ClearPrefDir();
12606  int TrackVectorPosition;
12607  TTrackElement TrackElement;
12608 
12609  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12610  {
12611  Utilities->CallLogPop(126);
12612  return(false);
12613  }
12614 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12615  if(TrackElement.TrackType == Points)
12616  {
12617  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12618  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12619  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12620  //best to prevent it to avoid problems
12621  Utilities->CallLogPop(127);
12622  return false;
12623  }
12624 */
12625  TPrefDirElement PrefDirElement(TrackElement);
12626 
12627  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12628  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12629  StorePrefDirElement(1, PrefDirElement); // enter first element
12630 // Note that ELink not set even if a buffer or continuation - these set in
12631 // ConvertPrefDirSearchVector after 2nd element added
12632 
12633  Utilities->CallLogPop(128);
12634  return(true);
12635 }
12636 
12637 // ---------------------------------------------------------------------------
12638 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12639 
12640 /*
12641  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12642  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12643  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12644  with setting the PrefDir vector, & return true.
12645  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12646  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12647  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12648  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12649  ConvertPrefDirSearchVector to set PrefDirVector.
12650  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12651  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12652  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12653 */
12654 
12655 {
12656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12657  FinishElement = false;
12658  int TrackVectorPosition;
12659 
12660  TotalSearchCount = 0;
12661  TTrackElement TrackElement, TempTrackElement;
12662 
12663  if(PrefDirVector.size() == 0)
12664  {
12665  Utilities->CallLogPop(129);
12666  return(false);
12667  }
12668  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12669  {
12670  Utilities->CallLogPop(130);
12671  return(false);
12672  }
12673 // set the search limits using the last stored element in PrefDirVector as the start point
12674 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12675 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12676 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12677 
12678  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12679 
12680  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12681  {
12682  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12683  SearchLimitHighH = TrackElement.HLoc + 15;
12684  }
12685  else
12686  {
12687  SearchLimitLowH = TrackElement.HLoc - 15;
12688  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12689  }
12690  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12691  {
12692  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12693  SearchLimitHighV = TrackElement.VLoc + 15;
12694  }
12695  else
12696  {
12697  SearchLimitLowV = TrackElement.VLoc - 15;
12698  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12699  }
12700 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12701  check & TotalSearchCounts check
12702  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12703  {
12704  ShowMessage("Unable to reach the selected element - too far ahead");
12705  Utilities->CallLogPop(1692);
12706  return false;
12707  }
12708 */
12709 // get last PrefDir element
12710  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12711  {
12712  // check if TrackElement adjacent to any of the 4 XLinkPos'
12713  for(int x = 0; x < 4; x++)
12714  {
12715  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12716  {
12717  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12718  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12719  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12720  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12721  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12722  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12723  // shouldn't ever get it in a serious railway though.
12724 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12725  }
12726  }
12727  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12728  {
12729  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12730  SearchVector.clear(); // use this & convert to set all PrefDir element values
12731  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12732  {
12734  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12735  {
12736  FinishElement = true;
12737  }
12738  Utilities->CallLogPop(131);
12739  return(true);
12740  }
12741  } // not an adjacent element
12742 
12743  // now check each of the 4 possible XLinkPos values
12744  for(int x = 0; x < 4; x++)
12745  {
12746  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12747  {
12748  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12749  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12750  SearchVector.clear();
12751  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12752  {
12754  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12755  {
12756  FinishElement = true;
12757  }
12758  Utilities->CallLogPop(132);
12759  return(true);
12760  }
12761  }
12762  } // here if checked all possible exits without success
12763  ShowMessage(
12764  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12765  Utilities->CallLogPop(133);
12766  return(false);
12767  }
12768 // dealt above with LastPrefDirElement being the start element (which can be points)
12769 
12770  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12771  .ELinkPos] == Lead)) // leading point
12772  {
12773  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12774  {
12775  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12776  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12777  // can't be buffers or gap if points
12778  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12779  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12780  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12781  SearchVector.clear();
12782  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12783  {
12785  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12786  {
12787  FinishElement = true;
12788  }
12789  Utilities->CallLogPop(134);
12790  return(true);
12791  }
12792  }
12793  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12794  {
12795  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12796  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12797  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12798  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12799  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12800  SearchVector.clear();
12801  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12802  {
12804  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12805  {
12806  FinishElement = true;
12807  }
12808  Utilities->CallLogPop(135);
12809  return(true);
12810  }
12811  }
12812 // above dealt with immediate finds for leading point,
12813 // now deal with ordinary searches for leading point
12814  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12815  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12816  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12817  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12818  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12819  SearchVector.clear();
12820  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12821  {
12823  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12824  {
12825  FinishElement = true;
12826  }
12827  Utilities->CallLogPop(136);
12828  return(true);
12829  }
12830  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12831  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12832  // note that CheckCount already increased to allow for XLinkPos & XLink
12833  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12834  SearchVector.clear();
12835  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12836  {
12838  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12839  {
12840  FinishElement = true;
12841  }
12842  Utilities->CallLogPop(137);
12843  return(true);
12844  }
12845 // here if failed to find match for leading point
12846  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12847  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12848  ShowMessage(
12849  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12850  Utilities->CallLogPop(138);
12851  return(false);
12852  }
12853 // leading point fully dealt with above
12854 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12855 // separately as covered in ordinary search.
12856 
12857  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12858  SearchVector.clear();
12859 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12860  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12861  {
12863  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12864  {
12865  FinishElement = true;
12866  }
12867  Utilities->CallLogPop(139);
12868  return(true);
12869  }
12870  ShowMessage(
12871  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12872  Utilities->CallLogPop(140);
12873  return(false); // failed to find required element
12874 }
12875 
12876 // ---------------------------------------------------------------------------
12877 
12878 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12879 /*
12880  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12881  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12882  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12883  Keep a count of entries in SearchVector during the current function call, so that this number can be
12884  erased for an unproductive branch search.
12885  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12886  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12887  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12888  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12889  If not any of above, store element in searchvector, set the new current element values from the
12890  SearchElement, then go back to the while loop for the next step in the search.
12891 */
12892 {
12893  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12894  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12895  int VectorCount = 0;
12896 
12897  while(true)
12898  {
12899  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12900  {
12901  for(int x = 0; x < VectorCount; x++)
12902  {
12903  SearchVector.erase(SearchVector.end() - 1);
12904  }
12905  Utilities->CallLogPop(141);
12906  return(false);
12907  }
12908  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12909  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12910  TPrefDirElement SearchElement(NextTrackElement);
12911  SearchElement.TrackVectorPosition = NextPosition;
12912  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12913  SearchElement.ELinkPos = NextELinkPos;
12914  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12915  int NextXLinkPos;
12916  if(SearchElement.ELinkPos == 0)
12917  {
12918  NextXLinkPos = 1;
12919  }
12920  if(SearchElement.ELinkPos == 1)
12921  {
12922  NextXLinkPos = 0;
12923  }
12924  if(SearchElement.ELinkPos == 2)
12925  {
12926  NextXLinkPos = 3;
12927  }
12928  if(SearchElement.ELinkPos == 3)
12929  {
12930  NextXLinkPos = 2;
12931  }
12932  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12933  {
12934  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12935  // but may be buffers, continuation or gap
12936  SearchElement.XLinkPos = NextXLinkPos;
12937  }
12938 // can't set XLink or XLinkPos yet if the element is a leading point.
12939 // check if found it
12940  if(SearchElement.TrackVectorPosition == RequiredPosition)
12941  {
12942  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12943  VectorCount++; // not really needed but include for tidyness
12944  TotalSearchCount++;
12945  Utilities->CallLogPop(142);
12946  return(true);
12947  }
12948 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12949 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12950 // at a time - drop this
12951 /*
12952  if(PrefDirVector.size() > 200)
12953  {
12954  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12955  Utilities->CallLogPop(1419);
12956  return false;
12957  }
12958 */
12959 // check if a buffer or continuation
12960  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12961  {
12962  for(int x = 0; x < VectorCount; x++)
12963  {
12964  SearchVector.erase(SearchVector.end() - 1);
12965  }
12966  Utilities->CallLogPop(143);
12967  return(false);
12968  }
12969 // check if reached an earlier position on search PrefDir with same entry value
12970  for(unsigned int x = 0; x < SearchVector.size(); x++)
12971  {
12972  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12973  {
12974  for(int x = 0; x < VectorCount; x++)
12975  {
12976  SearchVector.erase(SearchVector.end() - 1);
12977  }
12978  Utilities->CallLogPop(144);
12979  return(false);
12980  }
12981  }
12982 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12983 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12984  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12985  {
12986  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12987  {
12988  for(int x = 0; x < VectorCount; x++)
12989  {
12990  SearchVector.erase(SearchVector.end() - 1);
12991  }
12992  Utilities->CallLogPop(1417);
12993  return(false);
12994  }
12995  }
12996 
12997 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12998 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12999 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13001  {
13002  for(int x = 0; x < VectorCount; x++)
13003  {
13004  SearchVector.erase(SearchVector.end() - 1);
13005  }
13006  Utilities->CallLogPop(1691);
13007  return(false);
13008  }
13009 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
13010  if(SearchVector.size() > 150)
13011  {
13012  for(int x = 0; x < VectorCount; x++)
13013  {
13014  SearchVector.erase(SearchVector.end() - 1);
13015  }
13016  Utilities->CallLogPop(1418);
13017  return(false);
13018  }
13019 // check if reached a leading point
13020  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13021  {
13022 // push element with XLink set to position [1]
13023  SearchElement.XLink = SearchElement.Link[1];
13024  SearchElement.XLinkPos = 1;
13025  SearchVector.push_back(SearchElement);
13026  VectorCount++;
13027  TotalSearchCount++;
13028  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
13029  // Note that have to use a TTrackElement in the recursive search, so SearchElement
13030  // can't be used. NextTrackElement is the corresponding TTrackElement.
13031  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
13032  {
13033  Utilities->CallLogPop(145);
13034  return(true);
13035  }
13036  else
13037  {
13038 // remove leading point with XLinkPos [1]
13039  SearchVector.erase(SearchVector.end() - 1);
13040  VectorCount--;
13041 // push element with XLink set to position [3]
13042  SearchElement.XLink = SearchElement.Link[3];
13043  SearchElement.XLinkPos = 3;
13044  SearchVector.push_back(SearchElement);
13045  VectorCount++;
13046  TotalSearchCount++;
13047 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
13048  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
13049  {
13050  Utilities->CallLogPop(146);
13051  return(true);
13052  }
13053  else
13054  {
13055  for(int x = 0; x < VectorCount; x++)
13056  {
13057  SearchVector.erase(SearchVector.end() - 1);
13058  }
13059  Utilities->CallLogPop(147);
13060  return(false);
13061  }
13062  }
13063  } // if leading point
13064 
13065 // here if ordinary element, push it, inc vector & update CurrentTrackElement
13066 // ready for next element on PrefDir
13067  SearchVector.push_back(SearchElement);
13068  VectorCount++;
13069  TotalSearchCount++;
13070  XLinkPos = NextXLinkPos;
13071  CurrentTrackElement = SearchElement;
13072  } // while(true)
13073 }
13074 
13075 // ---------------------------------------------------------------------------
13076 
13078 /*
13079  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
13080  for each element on the search PrefDir, though if the last element is a leading point
13081  then the final XLink won't be set.
13082  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
13083  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
13084  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
13085 */
13086 {
13087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
13088  if(SearchVector.size() == 0)
13089  {
13090  throw Exception("Error, SearchVector empty");
13091  }
13092 // get first SearchElement in order to set last PrefDirelement
13093  TPrefDirElement SearchElement = SearchVector.at(0);
13094 
13095 // set last PrefDir element XLink & ELink values if not already set
13096 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
13097  for(int x = 0; x < 4; x++)
13098  {
13099  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
13100  {
13101  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
13102  {
13103  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
13104  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
13105  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
13106  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
13107  }
13108  int ELinkPos;
13109  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
13110  {
13111  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
13112  }
13113  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
13114  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
13115  {
13116  ELinkPos = 0;
13117  }
13118  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
13119  {
13120  ELinkPos = 3;
13121  }
13122  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
13123  {
13124  ELinkPos = 2;
13125  }
13126  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
13127  {
13128  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
13129  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
13130  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
13131  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
13132  }
13133  break; // no point going any further
13134  }
13135  }
13136 // set EXNumber for last PrefDir element, unless already set
13137 // won't be set if was first element or a leading point
13138  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
13139  {
13140 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
13141  int EXArray[32][2] = {
13142  {4,6},{2,8}, //horizontal & vertical
13143  {2,4},{6,2},{8,6},{4,8}, //sharp curves
13144  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
13145  {1,9},{3,7} //forward & reverse diagonals
13146 */
13147 
13148  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
13149  {
13150  throw Exception("Error in EntryExitNumber 1");
13151  }
13152  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
13153  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
13154  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
13155  }
13156 // Last PrefDir element now complete
13157 
13158 // construct remaining PrefDir elements from searchvector
13159  for(unsigned int x = 0; x < SearchVector.size(); x++)
13160  {
13161  SearchElement = SearchVector.at(x);
13162  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
13163  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
13164  PrefDirElement.ELink = SearchElement.ELink;
13165  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
13166  PrefDirElement.XLink = SearchElement.XLink;
13167  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
13168 // if XLink & XLinkPos not set don't account for them in CheckCount
13169  if(PrefDirElement.XLink == -1)
13170  {
13171  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13172  }
13173  // & TrackVectorPosition
13174  else
13175  {
13176  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13177  }
13178  // XLink, XLinkPos, TrackVectorPosition
13179 
13180 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
13181  if(PrefDirElement.XLink != -1)
13182  {
13183  if(!(PrefDirElement.EntryExitNumber()))
13184  {
13185  throw Exception("Error in EntryExitNumber 2");
13186  }
13187  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
13188  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
13189  PrefDirElement.CheckCount++;
13190  // all values now incorporated if not a leading point
13191  }
13192 // store PrefDir element
13193  StorePrefDirElement(2, PrefDirElement);
13194  }
13195 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
13196  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
13197  {
13198  if(ValidatePrefDir(2))
13199  {
13200  ;
13201  } // error messages given within function
13202 
13203  }
13205 /* drop this, check dropped from search
13206  if(PrefDirVector.size() > 200)
13207  {
13208  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
13209  }
13210 */
13211  Utilities->CallLogPop(148);
13212 }
13213 
13214 // ---------------------------------------------------------------------------
13215 
13216 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
13217 /*
13218  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
13219  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
13220 */
13221 {
13222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
13223  LeadingPoints = false;
13224  if(PrefDirVector.empty())
13225  {
13226  Utilities->CallLogPop(1786);
13227  return(false); // should never be empty but allow for it for safety
13228  }
13229  if(PrefDirVector.size() == 1)
13230  {
13231  Utilities->CallLogPop(149);
13232  return(false); // can't end if only one element
13233  }
13234 /*
13235  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
13236  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
13237  {
13238  Utilities->CallLogPop(150);
13239  return true;
13240  }
13241 */
13242 // allow for anything but leading points
13243  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
13244  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
13245  {
13246  Utilities->CallLogPop(1776);
13247  return(true);
13248  }
13249  else
13250  {
13251  LeadingPoints = true;
13252  Utilities->CallLogPop(151);
13253  return(false);
13254  }
13255 }
13256 
13257 // ---------------------------------------------------------------------------
13258 
13260 /*
13261  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
13262  and that every element is connected to the next element
13263 */
13264 {
13265  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
13266  int Position;
13267  AnsiString ErrorString;
13268  bool Error = false;
13269 
13270  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13271  {
13272  if(PrefDirVector.at(x).HLoc == -2000000000)
13273  {
13274  Error = true;
13275  ErrorString = "HLoc";
13276  Position = x;
13277  }
13278  if(PrefDirVector.at(x).VLoc == -2000000000)
13279  {
13280  Error = true;
13281  ErrorString = "VLoc";
13282  Position = x;
13283  }
13284  if(PrefDirVector.at(x).ELink == -1)
13285  {
13286  Error = true;
13287  ErrorString = "ELink";
13288  Position = x;
13289  }
13290  if(PrefDirVector.at(x).ELinkPos == -1)
13291  {
13292  Error = true;
13293  ErrorString = "ELinkPos";
13294  Position = x;
13295  }
13296  if(PrefDirVector.at(x).XLink == -1)
13297  {
13298  Error = true;
13299  ErrorString = "XLink";
13300  Position = x;
13301  }
13302  if(PrefDirVector.at(x).XLinkPos == -1)
13303  {
13304  Error = true;
13305  ErrorString = "XLinkPos";
13306  Position = x;
13307  }
13308  if(PrefDirVector.at(x).SpeedTag == 0)
13309  {
13310  Error = true;
13311  ErrorString = "Tag";
13312  Position = x;
13313  }
13314  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13315  {
13316  Error = true;
13317  ErrorString = "TrackVectorPosition";
13318  Position = x;
13319  }
13320  if(PrefDirVector.at(x).EXNumber == -1)
13321  {
13322  Error = true;
13323  ErrorString = "EXNumber";
13324  Position = x;
13325  }
13326  if(PrefDirVector.at(x).CheckCount != 9)
13327  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13328  {
13329  Error = true;
13330  ErrorString = "CheckCount";
13331  Position = x;
13332  }
13333 // extra checks
13334  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13335  {
13336  Error = true;
13337  ErrorString = "EntryGraphicPtr";
13338  Position = x;
13339  }
13340  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13341  {
13342  Error = true;
13343  ErrorString = "EntryDirectionGraphicPtr";
13344  Position = x;
13345  }
13346 // end of extra checks
13347  if(x > 0)
13348  {
13349  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13350  {
13351  Error = true;
13352  ErrorString = "Last XLink not connected to this element";
13353  Position = x;
13354  }
13355  }
13356  }
13357  if(Error)
13358  {
13359  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13360  }
13361  else
13362  {
13363  Utilities->CallLogPop(153);
13364  return(true);
13365  }
13366 }
13367 
13368 // ---------------------------------------------------------------------------
13369 
13370 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13371 /*
13372  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13373  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13374  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13375  or a leading point.
13376 */
13377 {
13378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13379  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13380  {
13381  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13382  {
13383  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13384  {
13385  ErasePrefDirElementAt(1, PrefDirVecPos);
13386  }
13387  if(PrefDirVector.size() == 0)
13388  {
13389  Utilities->CallLogPop(154);
13390  return(true);
13391  }
13392  if(PrefDirVector.size() == 1)
13393  {
13394  PrefDirVector.at(x - 1).ELinkPos = -1;
13395  PrefDirVector.at(x - 1).ELink = -1;
13396  PrefDirVector.at(x - 1).XLinkPos = -1;
13397  PrefDirVector.at(x - 1).XLink = -1;
13398  PrefDirVector.at(x - 1).EXNumber = -1;
13399  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13400  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13401  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13402  Utilities->CallLogPop(155);
13403  return(true);
13404  }
13405  // here with truncate element not first element, so ELink & ELinkPos set
13406  // unset XLink & Pos if a leading point
13407  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13408  {
13409  PrefDirVector.at(x - 1).XLinkPos = -1;
13410  PrefDirVector.at(x - 1).XLink = -1;
13411  PrefDirVector.at(x - 1).EXNumber = -1;
13412  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13413  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13414  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13415  Utilities->CallLogPop(156);
13416  return(true);
13417  }
13418  Utilities->CallLogPop(157);
13419  return(true);
13420  }
13421  }
13422  Utilities->CallLogPop(158);
13423  return(false);
13424 }
13425 
13426 // ---------------------------------------------------------------------------
13427 
13428 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13429 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13430 /*
13431  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13432  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13433  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13434  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13435  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13436  displayed.
13437 */
13438 {
13439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13440  AnsiString((short)BuildingPrefDir));
13441  int HPos, VPos;
13442 
13443  if(PrefDirSize() == 0)
13444  {
13445  Utilities->CallLogPop(159);
13446  return;
13447  }
13448  for(unsigned int x = 0; x < PrefDirSize(); x++)
13449  {
13450  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13451 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13452 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13453 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13454  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13455  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13456  // only the front half of which will be overplotted by the back of the train, then when the train is
13457  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13458  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13459  {
13460  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13461  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13462  {
13463  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13464  }
13465  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13466  // Route, no direction if a single element
13467  {
13468  if(x == 0)
13469  {
13470  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13471  }
13472  if(x == (PrefDirSize() - 1))
13473  {
13474  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13475  }
13476  }
13477  }
13478  }
13479 
13480 // set start & end element colours if building a PrefDir
13481  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13482  {
13483  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13484  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13485  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13486  // set last element colour
13487  if(PrefDirSize() > 1)
13488  {
13489  unsigned int LatestPos = PrefDirSize() - 1;
13490  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13491  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13492  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13493  }
13494  }
13495  Disp->Update();
13496  Utilities->CallLogPop(160);
13497 }
13498 
13499 // ---------------------------------------------------------------------------
13500 
13502 /*
13503  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13504  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13505 */
13506 {
13507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13508  if(PrefDirSize() == 0)
13509  {
13510  Utilities->CallLogPop(1547);
13511  return;
13512  }
13513  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13514  bool FoundFlag;
13516  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13517 
13518  while(MMIT != PrefDir4MultiMap.end())
13519  {
13520  H = MMIT->first.first;
13521  V = MMIT->first.second;
13522  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13523  // always found in order, any missing have PrefDirPosx == -1
13524  if(PrefDirPos0 > -1)
13525  {
13526  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13527  }
13528  if(PrefDirPos1 > -1)
13529  {
13530  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13531  }
13532  if(PrefDirPos2 > -1)
13533  {
13534  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13535  }
13536  if(PrefDirPos3 > -1)
13537  {
13538  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13539  }
13540  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13541  {
13542  // need to plot all 4 in order to obtain all the direction graphics
13543  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13544  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13545  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13546  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13547  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13548  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13549  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13550  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13551  MMIT++;
13552  MMIT++;
13553  MMIT++;
13554  MMIT++;
13555  }
13556  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13557  {
13558  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13559  {
13560  // 0 & 1 constitute the bidirectional PrefDir
13561  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13562  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13563  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13564  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13565  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13566  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13567  MMIT++;
13568  MMIT++;
13569  MMIT++;
13570  }
13571  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13572  {
13573  // 0 & 2 constitute the bidirectional PrefDir
13574  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13575  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13576  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13577  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13578  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13579  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13580  MMIT++;
13581  MMIT++;
13582  MMIT++;
13583  }
13584  else
13585  {
13586  // 1 & 2 constitute the bidirectional PrefDir
13587  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13588  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13589  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13590  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13591  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13592  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13593  MMIT++;
13594  MMIT++;
13595  MMIT++;
13596  }
13597  }
13598  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13599  {
13600  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13601  {
13602  // 0 & 1 constitute the bidirectional PrefDir
13603  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13604  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13605  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13606  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13607  MMIT++;
13608  MMIT++;
13609  }
13610  else
13611  {
13612  // 2 unidirectional PrefDirs
13613  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13614  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13615  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13616  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13617  MMIT++;
13618  MMIT++;
13619  }
13620  }
13621  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13622  {
13623  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13624  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13625  MMIT++;
13626  }
13627  }
13628  Disp->Update();
13629  Utilities->CallLogPop(1548);
13630 }
13631 
13632 // ---------------------------------------------------------------------------
13633 
13634 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13635 {
13636  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13637  int TempInt;
13638 
13639  ClearPrefDir();
13640  int NumberOfPrefDirElements = 0;
13641 
13642  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13643  for(int x = 0; x < NumberOfPrefDirElements; x++)
13644  {
13645  VecFile >> TempInt; // TrackVectorPosition
13646  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13647  LoadPrefDirElement.TrackVectorPosition = TempInt;
13648  VecFile >> TempInt;
13649  LoadPrefDirElement.ELink = TempInt;
13650  VecFile >> TempInt;
13651  LoadPrefDirElement.ELinkPos = TempInt;
13652  VecFile >> TempInt;
13653  LoadPrefDirElement.XLink = TempInt;
13654  VecFile >> TempInt;
13655  LoadPrefDirElement.XLinkPos = TempInt;
13656  VecFile >> TempInt;
13657  LoadPrefDirElement.EXNumber = TempInt;
13658  VecFile >> TempInt;
13659  LoadPrefDirElement.CheckCount = TempInt;
13660  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13661  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13662  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13663  if(!(LoadPrefDirElement.IsARoute))
13664  {
13665  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13666  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13667  }
13668  else
13669  {
13670  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13671  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13672  LoadPrefDirElement.PrefDirRoute);
13673  }
13674  StorePrefDirElement(5, LoadPrefDirElement);
13675  Utilities->LoadFileString(VecFile); // marker
13676  }
13678  Utilities->CallLogPop(161);
13679 }
13680 
13681 // ---------------------------------------------------------------------------
13682 
13683 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13684 {
13685  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13686  int TempInt;
13687 
13688  ClearPrefDir();
13689  int NumberOfPrefDirElements = 0;
13690 
13691  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13692  for(int x = 0; x < NumberOfPrefDirElements; x++)
13693  {
13694  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13695  VecFile >> TempInt; // TrackVectorPosition
13696  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13697  LoadPrefDirElement.TrackVectorPosition = TempInt;
13698  VecFile >> TempInt;
13699  LoadPrefDirElement.ELink = TempInt;
13700  VecFile >> TempInt;
13701  LoadPrefDirElement.ELinkPos = TempInt;
13702  VecFile >> TempInt;
13703  LoadPrefDirElement.XLink = TempInt;
13704  VecFile >> TempInt;
13705  LoadPrefDirElement.XLinkPos = TempInt;
13706  VecFile >> TempInt;
13707  LoadPrefDirElement.EXNumber = TempInt;
13708  VecFile >> TempInt;
13709  LoadPrefDirElement.CheckCount = TempInt;
13710  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13711  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13712  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13713  if(!(LoadPrefDirElement.IsARoute))
13714  {
13715  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13716  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13717  }
13718  else
13719  {
13720  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13721  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13722  LoadPrefDirElement.PrefDirRoute);
13723  }
13724  StorePrefDirElement(0, LoadPrefDirElement);
13725  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13726  }
13728  Utilities->CallLogPop(1509);
13729 }
13730 
13731 // ---------------------------------------------------------------------------
13732 
13733 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13734 /*
13735  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13736  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13737 */
13738 {
13739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13740  int TempInt;
13741  int NumberOfPrefDirElements = 0;
13742 
13743  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13744  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13745  {
13746  Utilities->CallLogPop(1152);
13747  return(false);
13748  }
13749  for(int x = 0; x < NumberOfPrefDirElements; x++)
13750  {
13751  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13752  {
13753  Utilities->CallLogPop(1766);
13754  return(false);
13755  }
13756  VecFile >> TempInt;
13757  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13758  {
13759  Utilities->CallLogPop(163);
13760  return(false);
13761  }
13762  VecFile >> TempInt;
13763  if((TempInt < -1) || (TempInt > 9)) // ELink
13764  {
13765  Utilities->CallLogPop(162);
13766  return(false);
13767  }
13768  VecFile >> TempInt;
13769  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13770  {
13771  Utilities->CallLogPop(164);
13772  return(false);
13773  }
13774  VecFile >> TempInt;
13775  if((TempInt < -1) || (TempInt > 9)) // XLink
13776  {
13777  Utilities->CallLogPop(165);
13778  return(false);
13779  }
13780  VecFile >> TempInt;
13781  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13782  {
13783  Utilities->CallLogPop(166);
13784  return(false);
13785  }
13786  VecFile >> TempInt;
13787  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13788  {
13789  Utilities->CallLogPop(167);
13790  return(false);
13791  }
13792  VecFile >> TempInt;
13793  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13794  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13795  // ELinkPos, XLink, XLinkPos & EXNumber
13796  {
13797  Utilities->CallLogPop(168);
13798  return(false);
13799  }
13800  VecFile >> TempInt;
13801  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13802  {
13803  Utilities->CallLogPop(1147);
13804  return(false);
13805  }
13806  VecFile >> TempInt;
13807  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13808  {
13809  Utilities->CallLogPop(1510);
13810  return(false);
13811  }
13812  VecFile >> TempInt;
13813  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13814  {
13815  Utilities->CallLogPop(1148);
13816  return(false);
13817  }
13818  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13819  {
13820  Utilities->CallLogPop(1700);
13821  return(false);
13822  }
13823  }
13824  Utilities->CallLogPop(169);
13825  return(true);
13826 }
13827 
13828 // ---------------------------------------------------------------------------
13829 
13830 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13831 {
13832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13833  int NumberOfPrefDirElements = PrefDirVector.size();
13834 
13835  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13836  for(int y = 0; y < NumberOfPrefDirElements; y++)
13837  {
13838  VecFile << y << '\n'; // extra
13839  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13840  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13841  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13842  VecFile << PrefDirVector.at(y).XLink << '\n';
13843  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13844  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13845  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13846  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13847  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13848  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13849  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13850  {
13851  VecFile << "************" << '\0' << '\n'; // marker
13852  }
13853  else
13854  {
13855  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13856  }
13857  }
13858  Utilities->CallLogPop(170);
13859 }
13860 
13861 // ---------------------------------------------------------------------------
13862 
13863 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13864 {
13865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13866  int NumberOfSearchElements = SearchVector.size();
13867 
13868  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13869  for(int y = 0; y < NumberOfSearchElements; y++)
13870  {
13871  VecFile << y << '\n'; // extra
13872  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13873  VecFile << SearchVector.at(y).ELink << '\n';
13874  VecFile << SearchVector.at(y).ELinkPos << '\n';
13875  VecFile << SearchVector.at(y).XLink << '\n';
13876  VecFile << SearchVector.at(y).XLinkPos << '\n';
13877  VecFile << SearchVector.at(y).EXNumber << '\n';
13878  VecFile << SearchVector.at(y).CheckCount << '\n';
13879  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13880  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13881  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13882  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13883  {
13884  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13885  }
13886  else
13887  {
13888  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13889  }
13890  }
13891  Utilities->CallLogPop(1847);
13892 }
13893 
13894 // ---------------------------------------------------------------------------
13895 
13896 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13897 /*
13898  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13899  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13900 */
13901 {
13902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13903  AnsiString(VLoc));
13904  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13905 
13906  if(VecPos > -1)
13907  {
13908  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13909  }
13910  else
13911  {
13912  Utilities->CallLogPop(171);
13913  return;
13914  }
13915  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13916  if(VecPos > -1)
13917  {
13918  ErasePrefDirElementAt(3, VecPos);
13919  }
13920  else
13921  {
13922  Utilities->CallLogPop(172);
13923  return;
13924  }
13925  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13926  if(VecPos > -1)
13927  {
13928  ErasePrefDirElementAt(4, VecPos);
13929  }
13930  else
13931  {
13932  Utilities->CallLogPop(173);
13933  return;
13934  }
13935  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13936  if(VecPos > -1)
13937  {
13938  ErasePrefDirElementAt(5, VecPos);
13939  }
13940  else
13941  {
13942  Utilities->CallLogPop(174);
13943  return;
13944  }
13945  Utilities->CallLogPop(175);
13946 }
13947 
13948 // ---------------------------------------------------------------------------
13949 /*
13950  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13951  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13952 
13953  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13954  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13955  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13956  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13957  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13958  PrefDirVector to correspond to the new track layout.
13959 
13960  {
13961  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13962  if(PrefDirSize() == 0)
13963  {
13964  Utilities->CallLogPop(176);
13965  return;
13966  }
13967  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13968  {
13969  int TV = PrefDirVector.at(x).TrackVectorPosition;
13970  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13971  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13972  if(Track->BlankElementAt(0, TV))
13973  {
13974  ErasePrefDirElementAt(6, x);
13975  }
13976  //if was a blankelement at x then ConnELink and ConnXLink both -1
13977  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13978  {
13979  ErasePrefDirElementAt(7, x);
13980  }
13981  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13982  //needs to be erased once, but if don't use 'else' then will erase two elements
13983  //since 'x' will correspond to the element after the first erased element
13984  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13985  {
13986  ErasePrefDirElementAt(8, x);
13987  }
13988  }
13989  Utilities->CallLogPop(177);
13990  }
13991 */
13992 // ---------------------------------------------------------------------------
13993 
13994 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13995 /*
13996  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13997  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13998 */
13999 {
14000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
14001  bool AlreadyPresent, FoundFlag;
14002  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14003 
14004  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
14005  {
14006  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
14007  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14008  AlreadyPresent = false;
14009  if(FoundFlag)
14010  {
14011  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
14012  {
14013  AlreadyPresent = true;
14014  }
14015  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
14016  {
14017  AlreadyPresent = true;
14018  }
14019  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
14020  {
14021  AlreadyPresent = true;
14022  }
14023  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
14024  {
14025  AlreadyPresent = true;
14026  }
14027  }
14028  if(!AlreadyPresent)
14029  {
14030  StorePrefDirElement(4, TempElement);
14031  }
14032  }
14034  Utilities->CallLogPop(178);
14035 }
14036 /* earlier brute force search
14037  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
14038  {
14039  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
14040  bool AlreadyPresent = false;
14041  for(unsigned int y = 0;y<PrefDirSize();y++)
14042  {
14043  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
14044  }
14045  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
14046  }
14047 */
14048 
14049 // ---------------------------------------------------------------------------
14050 
14052 /*
14053  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
14054  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
14055  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
14056  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
14057  positions are likely to have changed, so this function is called to reset all the necessary connections and
14058  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
14059  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
14060  shouldn't have changed.
14061 */
14062 {
14063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
14064  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14065  {
14066  bool FoundFlag;
14067  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14068  if(FoundFlag)
14069  {
14070  PrefDirVector.at(x).TrackVectorPosition = VecPos;
14071  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
14072  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
14073  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
14074  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
14075  for(unsigned int z = 0; z < 4; z++)
14076  {
14077  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
14078  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
14079  }
14080  }
14081  else
14082  {
14083  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
14084  }
14085  }
14086  Utilities->CallLogPop(179);
14087 }
14088 
14089 // ---------------------------------------------------------------------------
14090 
14092 /*
14093  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
14094 */
14095 {
14096  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
14097  bool DiscrepancyFound = false;
14098 
14099  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14100  {
14101  bool FoundFlag;
14102  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14103  if(FoundFlag)
14104  {
14105  TPrefDirElement PE = PrefDirVector.at(x);
14106  if(PE.TrackVectorPosition != VecPos)
14107  {
14108  DiscrepancyFound = true;
14109  break;
14110  }
14111  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14112  {
14113  DiscrepancyFound = true;
14114  break;
14115  }
14116  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14117  {
14118  DiscrepancyFound = true;
14119  break;
14120  }
14121  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
14122  {
14123  DiscrepancyFound = true;
14124  break;
14125  }
14126  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
14127  {
14128  DiscrepancyFound = true;
14129  break;
14130  }
14131  }
14132  else
14133  {
14134  DiscrepancyFound = true;
14135  }
14136  }
14137  if(DiscrepancyFound)
14138  {
14139  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
14140  ClearPrefDir(); // also clears multimap
14141  }
14142  Utilities->CallLogPop(1436);
14143 }
14144 
14145 // ---------------------------------------------------------------------------
14146 
14148 /*
14149  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
14150  return true for OK
14151 */
14152 {
14153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
14154  bool DiscrepancyFound = false;
14155 
14156  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14157  {
14158  bool FoundFlag;
14159  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14160  if(FoundFlag)
14161  {
14162  TPrefDirElement PE = PrefDirVector.at(x);
14163  if(PE.TrackVectorPosition != VecPos)
14164  {
14165  DiscrepancyFound = true;
14166  }
14167  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14168  {
14169  DiscrepancyFound = true;
14170  break;
14171  }
14172  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14173  {
14174  DiscrepancyFound = true;
14175  break;
14176  }
14177  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
14178  {
14179  DiscrepancyFound = true;
14180  break;
14181  }
14182  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
14183  {
14184  DiscrepancyFound = true;
14185  break;
14186  }
14187  }
14188  else
14189  {
14190  DiscrepancyFound = true;
14191  }
14192  }
14193  Utilities->CallLogPop(1512);
14194  return(!DiscrepancyFound);
14195 }
14196 
14197 // ---------------------------------------------------------------------------
14198 
14199 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
14200 /*
14201  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
14202  turn and for the overall sizes.
14203 */
14204 {
14205  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
14206  bool FoundFlag = false;
14207  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
14208 
14209  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
14210  {
14211  TPrefDirElement CheckElement = PrefDirVector.at(a);
14212  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
14213  if(!FoundFlag)
14214  {
14215  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
14216  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
14217  }
14218  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
14219  {
14220  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
14221  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
14222  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
14223  }
14224  }
14225  if(PrefDirVector.size() != PrefDir4MultiMap.size())
14226  {
14227  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
14228  + " Caller=" + (AnsiString)Caller);
14229  }
14230  Utilities->CallLogPop(180);
14231 }
14232 
14233 // ---------------------------------------------------------------------------
14234 
14235 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
14236  int &PrefDirPos3)
14237 /*
14238  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
14239  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
14240  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
14241  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
14242  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
14243 */
14244 {
14245  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
14246  AnsiString(VLoc));
14247  THVPair PrefDirMapKeyPair;
14248 
14249  PrefDirPos0 = -1;
14250  PrefDirPos1 = -1;
14251  PrefDirPos2 = -1;
14252  PrefDirPos3 = -1;
14253  FoundFlag = false;
14254  PrefDirMapKeyPair.first = HLoc;
14255  PrefDirMapKeyPair.second = VLoc;
14256  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14257 
14258  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
14259  if(ItPair.first == ItPair.second) //none found
14260  {
14261  Utilities->CallLogPop(181);
14262  return;
14263  }
14264  else
14265  {
14266  FoundFlag = true;
14267  PrefDirPos0 = ItPair.first->second;
14268  ItPair.first++;
14269  if(ItPair.first == ItPair.second)
14270  {
14271  Utilities->CallLogPop(182); //only one found
14272  return;
14273  }
14274  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14275  {
14276  PrefDirPos1 = ItPair.first->second;
14277  }
14278  ItPair.first++;
14279  if(ItPair.first == ItPair.second)
14280  {
14281  Utilities->CallLogPop(183); //2 found
14282  return;
14283  }
14284  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14285  {
14286  PrefDirPos2 = ItPair.first->second;
14287  }
14288  ItPair.first++;
14289  if(ItPair.first == ItPair.second)
14290  {
14291  Utilities->CallLogPop(184); //3 found
14292  return;
14293  }
14294  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14295  {
14296  PrefDirPos3 = ItPair.first->second; //4 found
14297  }
14298  }
14299  Utilities->CallLogPop(185);
14300 }
14301 
14302 // ---------------------------------------------------------------------------
14303 
14304 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14305 { //not used after modified the pref dir checking function at v2.13.0
14306  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14307  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14308  try
14309  {
14310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14311  + "," + AnsiString(LinkNumberPos));
14312  bool FoundFlag;
14313  int PD0, PD1, PD2, PD3;
14314  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14315  {
14316  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14317  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14318  PD0, PD1, PD2, PD3);
14319  if(!FoundFlag)
14320  {
14321  Utilities->CallLogPop(2282);
14322  return(false);
14323  }
14324  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14325  {
14326  if(PD0 > -1)
14327  {
14328  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14329  {
14330  LinkedPrefDirVectorNumber = PD0;
14331  Utilities->CallLogPop(2283);
14332  return(true);
14333  }
14334  }
14335  if(PD1 > -1)
14336  {
14337  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14338  {
14339  LinkedPrefDirVectorNumber = PD1;
14340  Utilities->CallLogPop(2284);
14341  return(true);
14342  }
14343  }
14344  }
14345  if(PD0 > -1)
14346  {
14347  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14348  {
14349  LinkedPrefDirVectorNumber = PD0;
14350  Utilities->CallLogPop(2285);
14351  return(true);
14352  }
14353  }
14354  if(PD1 > -1)
14355  {
14356  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14357  {
14358  LinkedPrefDirVectorNumber = PD1;
14359  Utilities->CallLogPop(2286);
14360  return(true);
14361  }
14362  }
14363  if(PD2 > -1)
14364  {
14365  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14366  {
14367  LinkedPrefDirVectorNumber = PD2;
14368  Utilities->CallLogPop(2287);
14369  return(true);
14370  }
14371  }
14372  if(PD3 > -1)
14373  {
14374  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14375  {
14376  LinkedPrefDirVectorNumber = PD3;
14377  Utilities->CallLogPop(2288);
14378  return(true);
14379  }
14380  }
14381  LinkedPrefDirVectorNumber = -1;
14382  Utilities->CallLogPop(2289);
14383  return(false);
14384  }
14385  else //buffer or continuation, no link at position 0 but not a failure
14386  {
14387  LinkedPrefDirVectorNumber = -1;
14388  Utilities->CallLogPop(2290);
14389  return(true);
14390  }
14391  }
14392  catch(const Exception &e) //non error catch
14393  {
14394  LinkedPrefDirVectorNumber = -1;
14395  Utilities->CallLogPop(2291);
14396  return(false);
14397  }
14398 }
14399 
14400 // ---------------------------------------------------------------------------
14401 
14402 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14403 { //not used after modified the pref dir checking function at v2.13.0
14404  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14405  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14406  try
14407  {
14408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14409  + "," + AnsiString(LinkNumberPos));
14410  bool FoundFlag;
14411  int PD0, PD1, PD2, PD3;
14412  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14413  {
14414  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14415  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14416  PD0, PD1, PD2, PD3);
14417  if(!FoundFlag)
14418  {
14419  Utilities->CallLogPop(2468);
14420  return(false);
14421  }
14422  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14423  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14424  if(PD0 > -1)
14425  {
14426  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14427  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14428  {
14429  LinkedPrefDirVectorNumber = PD0;
14430  Utilities->CallLogPop(2469);
14431  return(true);
14432  }
14433  }
14434  if(PD1 > -1)
14435  {
14436  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14437  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14438  {
14439  LinkedPrefDirVectorNumber = PD1;
14440  Utilities->CallLogPop(2470);
14441  return(true);
14442  }
14443  }
14444  LinkedPrefDirVectorNumber = -1;
14445  Utilities->CallLogPop(2471);
14446  return(false);
14447  }
14448  if(PD0 > -1)
14449  {
14450  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14451  {
14452  LinkedPrefDirVectorNumber = PD0;
14453  Utilities->CallLogPop(2472);
14454  return(true);
14455  }
14456  }
14457  if(PD1 > -1)
14458  {
14459  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14460  {
14461  LinkedPrefDirVectorNumber = PD1;
14462  Utilities->CallLogPop(2473);
14463  return(true);
14464  }
14465  }
14466  if(PD2 > -1)
14467  {
14468  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14469  {
14470  LinkedPrefDirVectorNumber = PD2;
14471  Utilities->CallLogPop(2474);
14472  return(true);
14473  }
14474  }
14475  if(PD3 > -1)
14476  {
14477  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14478  {
14479  LinkedPrefDirVectorNumber = PD3;
14480  Utilities->CallLogPop(2475);
14481  return(true);
14482  }
14483  }
14484  LinkedPrefDirVectorNumber = -1;
14485  Utilities->CallLogPop(2476);
14486  return(false);
14487  }
14488  else //buffer or continuation, no link at position 0 but not a failure
14489  {
14490  LinkedPrefDirVectorNumber = -1;
14491  Utilities->CallLogPop(2477);
14492  return(true);
14493  }
14494  }
14495  catch(const Exception &e) //non error catch
14496  {
14497  LinkedPrefDirVectorNumber = -1;
14498  Utilities->CallLogPop(2478);
14499  return(false);
14500  }
14501 }
14502 
14503 // ---------------------------------------------------------------------------
14504 
14506 {
14507  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14508  bool FoundFlag; //not used
14509  int PD0, PD1, PD2, PD3;
14510  //recover all PDs at the H & V of PDPtr
14511  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14512 
14513  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14514  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14515 
14516  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14517  {
14518  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14519  {
14520  Utilities->CallLogPop(2292);
14521  return(true);
14522  }
14523  }
14524  if(PD1 > -1)
14525  {
14526  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14527  {
14528  Utilities->CallLogPop(2293);
14529  return(true);
14530  }
14531  }
14532  if(PD2 > -1)
14533  {
14534  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14535  {
14536  Utilities->CallLogPop(2294);
14537  return(true);
14538  }
14539  }
14540  if(PD3 > -1)
14541  {
14542  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14543  {
14544  Utilities->CallLogPop(2295);
14545  return(true);
14546  }
14547  }
14548  Utilities->CallLogPop(2296);
14549  return(false);
14550 }
14551 
14552 // ---------------------------------------------------------------------------
14553 
14554 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14555 /*
14556  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14557 */
14558 {
14559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14560  PrefDirVector.push_back(LoadPrefDirElement);
14561  THVPair PrefDir4MultiMapKeyPair;
14562  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14563 
14564  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14565  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14566  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14567  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14568  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14569 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14570  Utilities->CallLogPop(186);
14571 }
14572 
14573 // ---------------------------------------------------------------------------
14574 
14575 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14576 /*
14577  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14578  4MultiMap if they are greater than the erased value.
14579 */
14580 {
14581  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14582  bool FoundFlag;
14583 
14584  if(!PrefDirVector.empty())
14585  {
14586  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14587  if(!FoundFlag)
14588  {
14589  throw Exception("Failed to find PrefDir4MultiMap erase element");
14590  }
14591  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14592  PrefDir4MultiMap.erase(EraseIt);
14593  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14595  }
14596  Utilities->CallLogPop(187);
14597 }
14598 
14599 // ---------------------------------------------------------------------------
14600 
14601 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14602 /*
14603  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14604  4MultiMap if they are greater than the erased value.
14605 */
14606 {
14607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14608  AnsiString(ErasedElementNumber));
14609  if(!PrefDir4MultiMap.empty())
14610  {
14611  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14612  {
14613  if(MapPtr->second > ErasedElementNumber)
14614  {
14615  MapPtr->second--;
14616  }
14617  }
14618  }
14619  Utilities->CallLogPop(1450);
14620 }
14621 
14622 // ---------------------------------------------------------------------------
14623 
14624 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14625 /*
14626  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14627  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14628  nothing is found this is an error but the error message is given in the calling function.
14629 */
14630 {
14631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14632  FoundFlag = false;
14633  if(PrefDirVectorPosition >= PrefDirVector.size())
14634  {
14635  throw Exception("PrefDirVectorPosition out of range");
14636  }
14637  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14638  THVPair PrefDir4MultiMapKeyPair;
14639 
14640  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14641  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14642  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14643 
14644  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14645  if(ItPair.first == ItPair.second)
14646  {
14647  Utilities->CallLogPop(188);
14648  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14649  }
14650  else
14651  {
14652  if(ItPair.first->second == PrefDirVectorPosition)
14653  {
14654  FoundFlag = true;
14655  Utilities->CallLogPop(189);
14656  return(ItPair.first);
14657  }
14658  ItPair.first++;
14659  if(ItPair.first == ItPair.second)
14660  {
14661  Utilities->CallLogPop(190);
14662  return(ItPair.first); // nothing found
14663  }
14664  if(ItPair.first->second == PrefDirVectorPosition)
14665  {
14666  FoundFlag = true;
14667  Utilities->CallLogPop(191);
14668  return(ItPair.first);
14669  }
14670  ItPair.first++;
14671  if(ItPair.first == ItPair.second)
14672  {
14673  Utilities->CallLogPop(192);
14674  return(ItPair.first); // nothing found
14675  }
14676  if(ItPair.first->second == PrefDirVectorPosition)
14677  {
14678  FoundFlag = true;
14679  Utilities->CallLogPop(193);
14680  return(ItPair.first);
14681  }
14682  ItPair.first++;
14683  if(ItPair.first == ItPair.second)
14684  {
14685  Utilities->CallLogPop(194);
14686  return(ItPair.first); // nothing found
14687  }
14688  if(ItPair.first->second == PrefDirVectorPosition)
14689  {
14690  FoundFlag = true;
14691  Utilities->CallLogPop(195);
14692  return(ItPair.first);
14693  }
14694  }
14695  Utilities->CallLogPop(196);
14696  return(ItPair.first); // nothing found
14697 }
14698 
14699 // ---------------------------------------------------------------------------
14700 
14701 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14702 /*
14703  Although there may be up to four entries at one H & V position this function gets just one. It is
14704  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14705  at H & V.
14706 */
14707 {
14708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14709  THVPair PrefDir4MultiMapKeyPair;
14710 
14711  PrefDir4MultiMapKeyPair.first = HLoc;
14712  PrefDir4MultiMapKeyPair.second = VLoc;
14713  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14714 
14715  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14716  if(ItPair.first == ItPair.second) // nothing found
14717  {
14718  Utilities->CallLogPop(197);
14719  return(-1);
14720  }
14721  else
14722  {
14723  Utilities->CallLogPop(198);
14724  return(ItPair.first->second);
14725  }
14726 }
14727 
14728 // ---------------------------------------------------------------------------
14729 
14730 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14731 {
14732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14733  bool ErasedFlag = false;
14734 
14735  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14736  {
14737  if(PrefDirSize() == 0)
14738  {
14739  Utilities->CallLogPop(1511);
14740  return;
14741  }
14742  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14743  {
14744  ErasedFlag = false;
14745  // use 'else' to ensure don't try to access an erased element
14746  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14747  {
14748  ErasePrefDirElementAt(11, x);
14749  ErasedFlag = true;
14750  }
14751  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14752  {
14753  ErasePrefDirElementAt(12, x);
14754  ErasedFlag = true;
14755  }
14756  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14757  {
14758  ErasePrefDirElementAt(13, x);
14759  ErasedFlag = true;
14760  }
14761  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14762  {
14763  ErasePrefDirElementAt(9, x);
14764  ErasedFlag = true;
14765  }
14766  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14767  {
14768  ErasePrefDirElementAt(10, x);
14769  ErasedFlag = true;
14770  }
14771  if(!ErasedFlag)
14772  {
14773  // don't use 'else' here as may be more than one that need decrementing
14774  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14775  {
14776  PrefDirVector.at(x).TrackVectorPosition--;
14777  }
14778  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14779  {
14780  PrefDirVector.at(x).Conn[0]--;
14781  }
14782  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14783  {
14784  PrefDirVector.at(x).Conn[1]--;
14785  }
14786  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14787  {
14788  PrefDirVector.at(x).Conn[2]--;
14789  }
14790  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14791  {
14792  PrefDirVector.at(x).Conn[3]--;
14793  }
14794  }
14795  }
14796  }
14797  Utilities->CallLogPop(1434);
14798 }
14799 
14800 // ---------------------------------------------------------------------------
14801 
14802 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14803 {
14804  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14805  OverallDistance = 0;
14806  OverallSpeedLimit = 0;
14807  LeadingPointsAtLastElement = false;
14808  if(PrefDirSize() == 0) // shouldn't be empty when this called
14809  {
14810  Utilities->CallLogPop(1491);
14811  return;
14812  }
14813  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14814  {
14815  LeadingPointsAtLastElement = true;
14816  Utilities->CallLogPop(1492);
14817  return;
14818  }
14819  for(unsigned int x = 0; x < PrefDirSize(); x++)
14820  {
14821  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14822  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14823  {
14824  OverallDistance += PrefDirElement.Length23;
14825  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14826  {
14827  if(x == 0)
14828  {
14829  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14830  }
14831  else
14832  {
14833  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14834  {
14835  OverallSpeedLimit = -1;
14836  }
14837  }
14838  }
14839  }
14840  else
14841  {
14842  OverallDistance += PrefDirElement.Length01;
14843  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14844  {
14845  if(x == 0)
14846  {
14847  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14848  }
14849  else
14850  {
14851  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14852  {
14853  OverallSpeedLimit = -1;
14854  }
14855  }
14856  }
14857  }
14858  }
14859  Utilities->CallLogPop(1529);
14860 }
14861 
14862 // ---------------------------------------------------------------------------
14863 
14864 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14865 {
14866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14867  if(PrefDirSize() == 0)
14868  {
14869  Utilities->CallLogPop(1564);
14870  return;
14871  }
14872  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14873  bool FoundFlag;
14875  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14876 
14877  while(MMIT != PrefDir4MultiMap.end())
14878  {
14879  HLoc = MMIT->first.first;
14880  VLoc = MMIT->first.second;
14881  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14882  H = HLoc - Track->GetHLocMin();
14883  V = VLoc - Track->GetVLocMin();
14884  // always found in order, any missing have PrefDirPosx == -1
14885  if(PrefDirPos0 > -1)
14886  {
14887  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14888  }
14889  if(PrefDirPos1 > -1)
14890  {
14891  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14892  }
14893  if(PrefDirPos2 > -1)
14894  {
14895  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14896  }
14897  if(PrefDirPos3 > -1)
14898  {
14899  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14900  }
14901  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14902  {
14903  // need to plot all 4 in order to obtain all the direction graphics
14904  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14905  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14906  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14907  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14908  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14909  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14910  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14911  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14912  MMIT++;
14913  MMIT++;
14914  MMIT++;
14915  MMIT++;
14916  }
14917  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14918  {
14919  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14920  {
14921  // 0 & 1 constitute the bidirectional PrefDir
14922  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14923  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14924  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14925  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14926  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14927  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14928  MMIT++;
14929  MMIT++;
14930  MMIT++;
14931  }
14932  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14933  {
14934  // 0 & 2 constitute the bidirectional PrefDir
14935  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14936  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14937  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14938  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14939  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14940  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14941  MMIT++;
14942  MMIT++;
14943  MMIT++;
14944  }
14945  else
14946  {
14947  // 1 & 2 constitute the bidirectional PrefDir
14948  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14949  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14950  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14951  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14952  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14953  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14954  MMIT++;
14955  MMIT++;
14956  MMIT++;
14957  }
14958  }
14959  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14960  {
14961  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14962  {
14963  // 0 & 1 constitute the bidirectional PrefDir
14964  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14965  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14966  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14967  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14968  MMIT++;
14969  MMIT++;
14970  }
14971  else
14972  {
14973  // 2 unidirectional PrefDirs
14974  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14975  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14976  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14977  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14978  MMIT++;
14979  MMIT++;
14980  }
14981  }
14982  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14983  {
14984  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14985  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14986  MMIT++;
14987  }
14988  }
14989  Utilities->CallLogPop(1565);
14990 }
14991 
14992 // ---------------------------------------------------------------------------
14993 
14994 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14995 /*
14996  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14997  level crossing, signals with wrong direction set, or buffers.
14998 */
14999 {
15000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
15001  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15002  bool FoundFlag;
15004  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
15005 
15006  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
15007  ElementIn.VLoc)))
15008  {
15009  Utilities->CallLogPop(1982);
15010  return(false);
15011  }
15012  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
15013  {
15014  Utilities->CallLogPop(1983);
15015  return(false);
15016  }
15017 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
15018  {
15019  Utilities->CallLogPop(1995);
15020  return(false);
15021  }
15022 */
15023 // Now check that there is only a single prefdir set
15024  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15025 // always found in order, any missing have PrefDirPosx == -1
15026  if(PrefDirPos0 > -1)
15027  {
15028  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
15029  }
15030  if(PrefDirPos1 > -1)
15031  {
15032  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
15033  }
15034  if(PrefDirPos2 > -1)
15035  {
15036  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
15037  }
15038  if(PrefDirPos3 > -1)
15039  {
15040  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
15041  }
15042  if(PrefDirPos3 > -1) // 4 found, all bidirectional
15043  {
15044  Utilities->CallLogPop(1984);
15045  return(false);
15046  }
15047  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
15048  {
15049  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
15050  {
15051  Utilities->CallLogPop(1985);
15052  return(false);
15053  }
15054  else
15055  {
15056  Utilities->CallLogPop(1986);
15057  return(true);
15058  }
15059  }
15060  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
15061  {
15062  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
15063  {
15064  Utilities->CallLogPop(1987);
15065  return(false);
15066  }
15067  else
15068  {
15069  Utilities->CallLogPop(1988);
15070  return(true);
15071  }
15072  }
15073  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
15074  {
15075  if(PrefDirElement0.XLinkPos == EntryPos)
15076  {
15077  Utilities->CallLogPop(1989);
15078  return(false);
15079  }
15080  else
15081  {
15082  Utilities->CallLogPop(1990);
15083  return(true);
15084  }
15085  }
15086  else
15087  {
15088  Utilities->CallLogPop(1991);
15089  return(false); // none found
15090  }
15091 }
15092 
15093 // ---------------------------------------------------------------------------
15094 
15096 {
15097 /* //Added at v2.1.0
15098  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
15099  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
15100  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
15101  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
15102  and can be modelled better anyway.
15103 
15104  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
15105  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
15106  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15107  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15108  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15109  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15110 */
15111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
15112  ElementIn.VLoc + "," + XLink);
15113  int TrackVecPos;
15114  bool TrackFoundFlag;
15115  TTrackElement TempTrackElement;
15116 
15117  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
15118  {
15119  Utilities->CallLogPop(2047);
15120  return(false);
15121  }
15122 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15123  if(XLink == 1)
15124  {
15125  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15126  if(TrackFoundFlag)
15127  {
15128  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
15129  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
15130  {
15131  Utilities->CallLogPop(2048);
15132  return(true);
15133  }
15134  }
15135  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15136  if(TrackFoundFlag)
15137  {
15138  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
15139  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
15140  {
15141  Utilities->CallLogPop(2049);
15142  return(true);
15143  }
15144  }
15145  }
15146 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15147  if(XLink == 3)
15148  {
15149  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15150  if(TrackFoundFlag)
15151  {
15152  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
15153  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
15154  {
15155  Utilities->CallLogPop(2050);
15156  return(true);
15157  }
15158  }
15159  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15160  if(TrackFoundFlag)
15161  {
15162  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
15163  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
15164  {
15165  Utilities->CallLogPop(2051);
15166  return(true);
15167  }
15168  }
15169  }
15170 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15171  if(XLink == 7)
15172  {
15173  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15174  if(TrackFoundFlag)
15175  {
15176  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
15177  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
15178  {
15179  Utilities->CallLogPop(2052);
15180  return(true);
15181  }
15182  }
15183  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15184  if(TrackFoundFlag)
15185  {
15186  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
15187  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
15188  {
15189  Utilities->CallLogPop(2053);
15190  return(true);
15191  }
15192  }
15193  }
15194 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15195  if(XLink == 9)
15196  {
15197  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15198  if(TrackFoundFlag)
15199  {
15200  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
15201  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
15202  {
15203  Utilities->CallLogPop(2054);
15204  return(true);
15205  }
15206  }
15207  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15208  if(TrackFoundFlag)
15209  {
15210  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
15211  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
15212  {
15213  Utilities->CallLogPop(2055);
15214  return(true);
15215  }
15216  }
15217  }
15218  Utilities->CallLogPop(2056);
15219  return(false);
15220 }
15221 
15222 // ---------------------------------------------------------------------------
15223 
15224 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
15225 {
15226 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
15227  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
15228  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
15229  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
15230  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
15231 */
15232  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
15234  bool FoundFlag, ContFlag, FoundElements = false;
15235  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15236  TPrefDirElement NextElement;
15237 
15238  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
15239  {
15240  LastIteratorValue++;
15241  ContFlag = false;
15242  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
15243  {
15244  continue;
15245  }
15246 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
15247  {
15248  continue;
15249  }
15250 */
15251 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
15252  // found a potential route start point
15253  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
15254  {
15255  continue;
15256  }
15257  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
15258  {
15259  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
15260  if(PDVIt->TrackType == Continuation)
15261  {
15262  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
15263  {
15264  continue;
15265  }
15266  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
15267  {
15268  continue;
15269  }
15270  }
15271  StartElement = *PDVIt;
15272 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
15273  // diverging track on which there was no pref dir. See below for 2 required changes.
15274  }
15275  else
15276  {
15277  continue;
15278  }
15279  // now track along until find a signal or continuation, checking validity for each element
15280  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
15281  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
15282  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15283  if(PrefDirPos0 == -1) // no continuing prefdir
15284  {
15285  continue;
15286  }
15287  bool NextElementFoundFlag = false;
15288  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15289  {
15290  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
15291  NextElementFoundFlag = true;
15292  }
15293  if(PrefDirPos1 > -1)
15294  {
15295  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15296  {
15297  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15298  NextElementFoundFlag = true;
15299  }
15300  }
15301  if(PrefDirPos2 > -1)
15302  {
15303  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15304  {
15305  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15306  NextElementFoundFlag = true;
15307  }
15308  }
15309  if(PrefDirPos3 > -1)
15310  {
15311  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15312  {
15313  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15314  NextElementFoundFlag = true;
15315  }
15316  }
15317  if(!NextElementFoundFlag)
15318  {
15319  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15320 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15321  }
15322  while(true)
15323  {
15324  // check validity
15325  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15326  {
15327  ContFlag = true;
15328  break;
15329  }
15330  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15331  {
15332  ContFlag = true;
15333  break;
15334  }
15335  // check if in a route, providing not a signal, as a signal might be at the start of a route
15336  if(NextElement.TrackType != SignalPost)
15337  {
15338  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15339  {
15340  ContFlag = true;
15341  break;
15342  }
15343  }
15344  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15345  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15346  {
15347  EndElement = NextElement;
15348  break;
15349  }
15350  // get the next element in the sequence
15351  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15352  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15353  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15354  if(PrefDirPos0 == -1) // no continuing prefdir
15355  {
15356  ContFlag = true;
15357  break;
15358  }
15359  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15360  {
15361  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15362  continue;
15363  }
15364  if(PrefDirPos1 > -1)
15365  {
15366  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15367  {
15368  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15369  continue;
15370  }
15371  }
15372  if(PrefDirPos2 > -1)
15373  {
15374  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15375  {
15376  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15377  continue;
15378  }
15379  }
15380  if(PrefDirPos3 > -1)
15381  {
15382  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15383  {
15384  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15385  continue;
15386  }
15387  }
15388  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15389  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15390  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15391  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15392  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15393  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15394  {
15395  ContFlag = true;
15396  break;
15397  }
15398  else
15399  {
15400  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15401  // could drop the bridge test but keep it to show the change history
15402  break;
15403 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15404  }
15405  }
15406  if(ContFlag)
15407  {
15408  continue;
15409  }
15410  // else have start and end elements set & all elements valid, so set up the route segment
15411  FoundElements = true;
15412  break;
15413  }
15414  if(FoundElements)
15415  {
15416  Utilities->CallLogPop(1992);
15417  return(true);
15418  }
15419  else
15420  {
15421  Utilities->CallLogPop(1993);
15422  return(false);
15423  }
15424 }
15425 
15426 // ---------------------------------------------------------------------------
15427 // TOneRoute
15428 // ---------------------------------------------------------------------------
15429 
15430 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15431 {
15432 /* General:
15433  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15434  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15435  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15436  route will use automatic signals or not.
15437  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15438  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15439  elements, so additional work is needed to complete all their members before they are ready for conversion into
15440  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15441  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15442  ConvertAndAdd.......
15443 */
15444  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15445  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15446  ClearRoute();
15447  int TrackVectorPosition;
15448  TTrackElement TrackElement;
15449  TPrefDirElement FirstElement, LastElement;
15450 
15451  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15452  {
15453  Utilities->CallLogPop(199);
15454  return(false);
15455  }
15456  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15457  {
15458  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15459  Utilities->CallLogPop(1996);
15460  return(false);
15461  }
15462  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15463  {
15464  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation to start or add to a route, or points to change them");
15465  Utilities->CallLogPop(200);
15466  return(false);
15467  }
15468  if(Track->IsLCAtHV(18, HLoc, VLoc))
15469  {
15470  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15471  Utilities->CallLogPop(1909);
15472  return(false);
15473  }
15474 // check if selected a train & disallow if so
15475  if(TrackElement.TrainIDOnElement > -1)
15476  {
15477  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15478  Utilities->CallLogPop(202);
15479  return(false);
15480  }
15481 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15482  TPrefDirElement PrefDirElement;
15483  int LockedVectorNumber;
15484 
15485  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15486  {
15487  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15488  Utilities->CallLogPop(203);
15489  return(false);
15490  }
15491  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15492  {
15493  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15494  Utilities->CallLogPop(204);
15495  return(false);
15496  }
15498  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15499 // signal in an autosig route & follow with a non-autosig route
15500 
15501  TPrefDirElement BlankElement;
15502 
15503  StartElement1 = BlankElement;
15504  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15505 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15506  bool InPrefDirFlag = false;
15507 
15508  bool FoundFlag;
15509  int PrefDirPos0 = -1;
15510  int PrefDirPos1 = -1;
15511  int PrefDirPos2 = -1;
15512  int PrefDirPos3 = -1;
15513 
15515  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15516  int PrefDirVecPos[4] =
15517  {
15518  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15519  };
15520 
15521  for(int x = 0; x < 4; x++)
15522  {
15523  int b = PrefDirVecPos[x];
15524  if(b > -1)
15525  {
15526  // only allow the appropriate exit route to be searched
15527  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15528  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15529  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15530  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15531  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15532  {
15533  InPrefDirFlag = true;
15534  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15535  if(AutoSigsFlag)
15536  {
15537  StartElement1.AutoSignals = true;
15538  }
15539  StartElement1.PrefDirRoute = true;
15540  }
15541  }
15542  }
15543 
15544  if(!InPrefDirFlag)
15545  {
15546  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15547  Utilities->CallLogPop(205);
15548  return(false);
15549  }
15550 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15552  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15553 
15554  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15555  {
15556  throw Exception("Selection in two routes - should never happen!");
15557  }
15558  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15559  {
15560  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15561  {
15562  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15563  Utilities->CallLogPop(206);
15564  return(false);
15565  }
15566  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15567  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15568  {
15569  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15570  Utilities->CallLogPop(207);
15571  return(false);
15572  }
15573  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15574  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15575  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15576  { //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
15577 // TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15578 // Utilities->CallLogPop(208);
15579 // return(false);
15580  }
15581  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15583  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15584  if(AutoSigsFlag)
15585  {
15586  StartElement1.AutoSignals = true;
15587  }
15588  StartElement1.PrefDirRoute = true;
15590  Utilities->CallLogPop(209);
15591  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15592  }
15593 
15594  else // no route started
15595  {
15596 // check if selected position is adjacent to start or end of an existing route and disallow
15597  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15598  {
15599  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15600  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15601  {
15602  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15603  Utilities->CallLogPop(210);
15604  return(false);
15605  }
15606  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15607  {
15608  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15609  Utilities->CallLogPop(211);
15610  return(false);
15611  }
15612  }
15613 
15614 // check if it's adjacent to end of an existing route,
15615  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15616  {
15618  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15619  {
15620  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15621  Utilities->CallLogPop(212);
15622  return(false);
15623  }
15624  }
15625  SearchVector.push_back(StartElement1);
15626  Utilities->CallLogPop(213);
15627  return(true);
15628  }
15629 }
15630 
15631 // ---------------------------------------------------------------------------
15632 
15633 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15634  IDInt &ReqPosRouteID, bool &PointsChanged)
15635 
15636 /*
15637  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15638 
15639  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15640  this being set to -1 for not used.
15641  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15642  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15643  Check correct type of element - signal/buffers/continuation.
15644  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15645  EndElement2 corresponding to the 2 possible PrefDir elements).
15646  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15647  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15648  linked forward to another route.
15649  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15650  for same position as start should cover this)
15651 
15652  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15653  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15654  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15655  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15656  If the search fails then return false.
15657  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15658  in the SearchVector to ensure it's entered as part of the new route.
15659  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15660  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15661  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15662  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15663  so return false, with an appropriate message if ConsecSignalsRoute set.
15664 */
15665 
15666 {
15667  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15668  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15669  int EndPosition; // the position selected
15670  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15671 
15672  Track->LCFoundInAutoSigsRoute = false;
15674  TotalSearchCount = 0;
15675  ReqPosRouteID = IDInt(-1); // default value for not used
15676  TTrackElement TrackElement;
15677  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15678  // given element as can't select 2-track elements
15679  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15680  {
15681  Utilities->CallLogPop(214);
15682  return(false);
15683  }
15684  if(Track->IsLCAtHV(19, HLoc, VLoc))
15685  {
15686  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15687  Utilities->CallLogPop(1908);
15688  return(false);
15689  }
15690 // cancel selection if on original start element
15691  if(EndPosition == StartRoutePosition)
15692  {
15693  Utilities->CallLogPop(215);
15694  return(false);
15695  }
15696  if(AutoSigsFlag)
15697  {
15698  if(TrackElement.TrackType == Buffers)
15699  {
15700  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15701  Utilities->CallLogPop(216);
15702  return(false);
15703  }
15704  }
15705  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15706  {
15707  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15708  Utilities->CallLogPop(217);
15709  return(false);
15710  }
15711 // check if train on element
15712  if(TrackElement.TrainIDOnElement > -1)
15713  {
15714  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15715  Utilities->CallLogPop(219);
15716  return(false);
15717  }
15718 // disallow if not in EveryPrefDir & set EndElement(s)
15719  bool InPrefDirFlag = false;
15720 
15721  bool FoundFlag;
15722  int PrefDirPos0 = -1;
15723  int PrefDirPos1 = -1;
15724  int PrefDirPos2 = -1;
15725  int PrefDirPos3 = -1;
15726 
15727  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15728  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15729  int PrefDirVecPos[4] =
15730  {
15731  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15732  };
15733 
15734  for(int x = 0; x < 4; x++)
15735  {
15736  int b = PrefDirVecPos[x];
15737  if(b > -1)
15738  {
15739  InPrefDirFlag = true;
15740  if(EndElement1.TrackVectorPosition == -1)
15741  {
15742  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15743  }
15744  else
15745  {
15746  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15747  }
15748  }
15749  }
15750  if(!InPrefDirFlag)
15751  {
15752  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15753  Utilities->CallLogPop(220);
15754  return(false);
15755  }
15756 // check if in an existing route - can't be a bridge so can use a simple 'find'
15757 // bool InRoute = false;
15759  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15760 
15761  if(RoutePair.first > -1)
15762  {
15763  if(RoutePair.second != 0) // not first element in existing route so no good
15764  {
15765  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15766  Utilities->CallLogPop(221);
15767  return(false);
15768  }
15769  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15770 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15771  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15772  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15773  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15774  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15775  {
15776  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15777  Utilities->CallLogPop(222);
15778  return(false);
15779  }
15780  EndElement1 = RouteElement;
15781  EndElement2 = BlankElement; // only need the route element
15782  EndPosition = EndElement1.TrackVectorPosition;
15783  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15784  }
15785 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15786 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15787 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15788 
15789  if(EndElement1.HLoc >= StartElement1.HLoc)
15790  {
15792  SearchLimitHighH = EndElement1.HLoc + 15;
15793  }
15794  else
15795  {
15796  SearchLimitLowH = EndElement1.HLoc - 15;
15798  }
15799  if(EndElement1.VLoc >= StartElement1.VLoc)
15800  {
15802  SearchLimitHighV = EndElement1.VLoc + 15;
15803  }
15804  else
15805  {
15806  SearchLimitLowV = EndElement1.VLoc - 15;
15808  }
15809 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15810  check & TotalSearchCounts check
15811  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15812  {
15813  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15814  Utilities->CallLogPop(1693);
15815  return false;
15816  }
15817 */
15818 // check if adjacent to start and disallow
15819  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15820  {
15822  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15823 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15824 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15825  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15826  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15827  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15828  {
15829  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15830  Utilities->CallLogPop(223);
15831  return(false);
15832  }
15833 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15834 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15835  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15836  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15837  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15838  {
15839  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15840  Utilities->CallLogPop(224);
15841  return(false);
15842  }
15843 // check if adjacent to end of a route & disallow
15845  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15846  {
15847  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15848  Utilities->CallLogPop(225);
15849  return(false);
15850  }
15851  }
15852 
15853 // check for same route as start element
15855  {
15856  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15857  Utilities->CallLogPop(226);
15858  return(false);
15859  }
15860 // check for a looping route
15861  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15862  {
15864  {
15865  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15866  Utilities->CallLogPop(1844);
15867  return(false);
15868  }
15869  }
15870 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15871 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15872 // and don't want to add it again
15873  if(StartSelectionRouteID > -1)
15874  {
15875  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15876  AutoSigsFlag, false))
15877  {
15878  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15879  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15880  {
15881  if(NewFailedPointsTVPos > -1)
15882  {
15883  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15884  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15885  " failed during route setting.");
15886  Utilities->CallLogPop(2488);
15887  return(false);
15888  }
15889  PointsChanged = true;
15890  }
15891  Utilities->CallLogPop(227);
15892  return(true);
15893  }
15894  else if(!Track->SuppressRouteFailMessage)
15895  {
15896  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15898  Utilities->CallLogPop(228);
15899  return(false);
15900  }
15901  }
15902  else
15903  {
15904 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15905 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15906 
15907 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15908 // note that a blank element will have XLinkPos set to -1
15909  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15910  {
15911  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15912  AutoSigsFlag, false))
15913  {
15914  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15915  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15916  {
15917  if(NewFailedPointsTVPos > -1)
15918  {
15919  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15920  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15921  " failed during route setting.");
15922  Utilities->CallLogPop(2490);
15923  return(false);
15924  }
15925  PointsChanged = true;
15926  }
15927  Utilities->CallLogPop(229);
15928  return(true);
15929  }
15930  else
15931  {
15933  {
15935  }
15936  Utilities->CallLogPop(230);
15937  return(false);
15938  }
15939  }
15940  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15941  {
15942  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15943  AutoSigsFlag, false))
15944  {
15945  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15946  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15947  {
15948  if(NewFailedPointsTVPos > -1)
15949  {
15950  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15951  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15952  " failed during route setting.");
15953  Utilities->CallLogPop(2492);
15954  return(false);
15955  }
15956  PointsChanged = true;
15957  }
15958  Utilities->CallLogPop(231);
15959  return(true);
15960  }
15961  else
15962  {
15964  {
15966  }
15967  Utilities->CallLogPop(232);
15968  return(false);
15969  }
15970  }
15971  // now start off in the best direction
15972  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15973  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15974  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15975  // unless new problems are found.
15976  if(StartElement1.XLinkPos == BestPos)
15977  {
15978  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15979  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15980  AutoSigsFlag, false))
15981  {
15982  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15983  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15984  {
15985  if(NewFailedPointsTVPos > -1)
15986  {
15987  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15988  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15989  " failed during route setting.");
15990  Utilities->CallLogPop(2494);
15991  return(false);
15992  }
15993  PointsChanged = true;
15994  }
15995  Utilities->CallLogPop(233);
15996  return(true);
15997  }
15998  else if(StartElement2.TrackVectorPosition > -1)
15999  {
16000  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16001  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16002  AutoSigsFlag, false))
16003  {
16004  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
16005  if(PointsToBeChanged(9, NewFailedPointsTVPos))
16006  {
16007  if(NewFailedPointsTVPos > -1)
16008  {
16009  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
16010  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
16011  " failed during route setting.");
16012  Utilities->CallLogPop(2496);
16013  return(false);
16014  }
16015  PointsChanged = true;
16016  }
16017  Utilities->CallLogPop(234);
16018  return(true);
16019  }
16020  }
16021  }
16022  else if(StartElement2.TrackVectorPosition > -1)
16023  {
16024  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16025  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16026  AutoSigsFlag, false))
16027  {
16028  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
16029  if(PointsToBeChanged(10, NewFailedPointsTVPos))
16030  {
16031  if(NewFailedPointsTVPos > -1)
16032  {
16033  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
16034  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
16035  " failed during route setting.");
16036  Utilities->CallLogPop(2498);
16037  return(false);
16038  }
16039  PointsChanged = true;
16040  }
16041  Utilities->CallLogPop(1857);
16042  return(true);
16043  }
16044  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16045  AutoSigsFlag, false))
16046  {
16047  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
16048  if(PointsToBeChanged(11, NewFailedPointsTVPos))
16049  {
16050  if(NewFailedPointsTVPos > -1)
16051  {
16052  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
16053  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
16054  " failed during route setting.");
16055  Utilities->CallLogPop(2500);
16056  return(false);
16057  }
16058  PointsChanged = true;
16059  }
16060  Utilities->CallLogPop(1858);
16061  return(true);
16062  }
16063  }
16064  else if(StartElement1.XLinkPos == (1 - BestPos))
16065  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
16066  {
16067  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16068  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16069  AutoSigsFlag, false))
16070  {
16071  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
16072  if(PointsToBeChanged(12, NewFailedPointsTVPos))
16073  {
16074  if(NewFailedPointsTVPos > -1)
16075  {
16076  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
16077  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
16078  " failed during route setting.");
16079  Utilities->CallLogPop(2502);
16080  return(false);
16081  }
16082  PointsChanged = true;
16083  }
16084  Utilities->CallLogPop(1864);
16085  return(true);
16086  }
16087  }
16088  }
16090  {
16092  }
16093  Utilities->CallLogPop(235);
16094  return(false);
16095 }
16096 
16097 // ---------------------------------------------------------------------------
16098 
16099 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
16100 {
16101  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
16102  if(PrefDirSize() == 0)
16103  {
16104  Utilities->CallLogPop(1704);
16105  return;
16106  }
16107  for(unsigned int x = 0; x < PrefDirSize(); x++)
16108  {
16109  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
16110  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
16111  {
16112  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16113  TempPrefDirElement.EXGraphicPtr);
16114  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
16115  {
16116  if(x == 0)
16117  {
16118  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16119  TempPrefDirElement.EntryDirectionGraphicPtr);
16120  }
16121  if(x == (PrefDirSize() - 1))
16122  {
16123  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16124  TempPrefDirElement.EntryDirectionGraphicPtr);
16125  }
16126  }
16127  }
16128  }
16129 
16130  Utilities->CallLogPop(1705);
16131 }
16132 
16133 // ---------------------------------------------------------------------------
16134 
16135 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
16136  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
16137 /*
16138  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
16139  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
16140  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
16141  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
16142  Return false if any element (apart from RequiredPosition) is on an existing route.
16143  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
16144 
16145  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
16146  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
16147  added during the function so as to leave it exactly as it was on entering, then return false).
16148  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
16149  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
16150  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
16151  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
16152  the route number that the searched-for element is the start of if any, and set to -1 if no
16153  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
16154  this unit, together with the ConsecSignals and AutoSigsFlag flags.
16155  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
16156  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
16157 
16158  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
16159  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
16160  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
16161  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
16162  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
16163  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
16164  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16165  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
16166  or if train on element (unless a bridge & train on different track).
16167  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
16168  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
16169  a leading point where both trailing directions are in EveryPrefDir, if not fail.
16170  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
16171  AutoSignals member set if AutoSigsFlag set, then return true.
16172  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
16173 
16174  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
16175  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
16176  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
16177  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
16178  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
16179  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
16180  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
16181 
16182  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
16183  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
16184 */
16185 
16186 {
16187  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
16188  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
16189  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
16190  int VectorCount = 0;
16191  if(!RecursiveCall) //added at v2.15.1
16192  {
16194  }
16195 
16196  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
16197 
16198 // check for a fouled diagonal for first element. Added for v1.3.2
16199  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
16200  {
16201  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
16202  {
16203  for(int x = 0; x < VectorCount; x++)
16204  {
16205  SearchVector.erase(SearchVector.end() - 1);
16206  }
16207  Utilities->CallLogPop(2043);
16208  return(false);
16209  }
16210  }
16211  bool FirstPass = true;
16212 
16213  while(true)
16214  {
16215  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
16216  {
16217  Track->LCFoundInAutoSigsRoute = true;
16218  }
16219  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
16220  {
16221  for(int x = 0; x < VectorCount; x++)
16222  {
16223  SearchVector.erase(SearchVector.end() - 1);
16224  }
16225  Utilities->CallLogPop(1926);
16226  return(false);
16227  }
16228  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
16229  {
16230  for(int x = 0; x < VectorCount; x++)
16231  {
16232  SearchVector.erase(SearchVector.end() - 1);
16233  }
16234  Utilities->CallLogPop(236);
16235  return(false);
16236  }
16237  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
16238  // reached a valid signal that isn't the required position, user should always select the next
16239  // signal in a route when ConsecSignals is true so have to fail
16240  // won't affect recurive searches as for them the first pass element is always a point
16241  {
16242  for(int x = 0; x < VectorCount; x++)
16243  {
16244  SearchVector.erase(SearchVector.end() - 1);
16245  }
16246  Utilities->CallLogPop(237);
16247  return(false);
16248  }
16249  FirstPass = false;
16250  int NextPosition = PrefDirElement.Conn[XLinkPos];
16251  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
16252  TPrefDirElement SearchElement(NextTrackElement);
16253  SearchElement.TrackVectorPosition = NextPosition;
16254  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
16255  SearchElement.ELinkPos = NextELinkPos;
16256  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
16257  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
16258  int NextXLinkPos;
16259  if(SearchElement.ELinkPos == 0)
16260  {
16261  NextXLinkPos = 1;
16262  }
16263  if(SearchElement.ELinkPos == 1)
16264  {
16265  NextXLinkPos = 0;
16266  }
16267  if(SearchElement.ELinkPos == 2)
16268  {
16269  NextXLinkPos = 3;
16270  }
16271  if(SearchElement.ELinkPos == 3)
16272  {
16273  NextXLinkPos = 2;
16274  }
16275  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16276  {
16277  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16278 // note that may be buffers, continuation or gap
16279  SearchElement.XLinkPos = NextXLinkPos;
16280  }
16281 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
16282 
16283 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16284  drop this at v2.16.1 as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of points and
16285  crossovers as can reach element on opposite track and still find the required end point - causes error when adding to the Route2MultiMap
16286  (happened by chance when developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search
16287  through all searchvector.
16288 
16289  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
16290 */
16291  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
16292  {
16293  for(unsigned int x = 0; x < SearchVector.size(); x++)
16294  {
16295  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
16296  {
16297  for(int x = 0; x < VectorCount; x++)
16298  {
16299  SearchVector.erase(SearchVector.end() - 1);
16300  }
16301  Utilities->CallLogPop(2653);
16302  return(false);
16303  }
16304  }
16305  }
16306  else if(SearchElement.TrackType == Bridge)
16307  {
16308  for(unsigned int x = 0; x < SearchVector.size(); x++)
16309  {
16310  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16311  (SearchElement.ELink == SearchVector.at(x).ELink))
16312  {
16313  for(int x = 0; x < VectorCount; x++)
16314  {
16315  SearchVector.erase(SearchVector.end() - 1);
16316  }
16317  Utilities->CallLogPop(2654);
16318  return(false);
16319  }
16320  }
16321  }
16322 
16323 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16324  TAllRoutes::TRouteElementPair SecondPair;
16326  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16327  if(RoutePair.first > -1)
16328  {
16329  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16330  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16331  RoutePair.second).ELinkPos)))
16332  {
16333  // still OK if start of an expected route
16334  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16335  {
16336  for(int x = 0; x < VectorCount; x++)
16337  {
16338  SearchVector.erase(SearchVector.end() - 1);
16339  }
16340  Utilities->CallLogPop(239);
16341  return(false); // only allow for start of an expected route
16342  }
16343  }
16344  }
16345  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16346  {
16347  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16348  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16349  SecondPair.second).ELinkPos)))
16350  {
16351  // still OK if start of an expected route
16352  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16353  {
16354  for(int x = 0; x < VectorCount; x++)
16355  {
16356  SearchVector.erase(SearchVector.end() - 1);
16357  }
16358  Utilities->CallLogPop(240);
16359  return(false); // only allow for start of an expected route
16360  }
16361  }
16362  }
16363 // check if a train on element, unless a bridge & train on different track
16364 // OK of same train as start element - no drop this
16365 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16366  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16367  {
16368  for(int x = 0; x < VectorCount; x++)
16369  {
16370  SearchVector.erase(SearchVector.end() - 1);
16371  }
16372  Utilities->CallLogPop(241);
16373  return(false);
16374  }
16375  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16376  {
16377  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16378  {
16379  for(int x = 0; x < VectorCount; x++)
16380  {
16381  SearchVector.erase(SearchVector.end() - 1);
16382  }
16383  Utilities->CallLogPop(242);
16384  return(false);
16385  }
16386  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16387  {
16388  for(int x = 0; x < VectorCount; x++)
16389  {
16390  SearchVector.erase(SearchVector.end() - 1);
16391  }
16392  Utilities->CallLogPop(243);
16393  return(false);
16394  }
16395  }
16396 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16397  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16398  {
16399  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16400  {
16401  for(int x = 0; x < VectorCount; x++)
16402  {
16403  SearchVector.erase(SearchVector.end() - 1);
16404  }
16405  Utilities->CallLogPop(244);
16406  return(false);
16407  }
16408  }
16409 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16410 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16411  bool InPrefDirFlag = false;
16412  PrefDirElement1 = BlankElement;
16413  PrefDirElement2 = BlankElement;
16414 
16415  bool FoundFlag;
16416  int PrefDirPos0 = -1;
16417  int PrefDirPos1 = -1;
16418  int PrefDirPos2 = -1;
16419  int PrefDirPos3 = -1;
16421  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16422  int PrefDirVecPos[4] =
16423  {
16424  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16425  };
16426  for(int x = 0; x < 4; x++)
16427  {
16428  int b = PrefDirVecPos[x];
16429  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16430  {
16431  InPrefDirFlag = true;
16432  if(PrefDirElement1.TrackVectorPosition == -1)
16433  {
16434  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16435  }
16436  else
16437  {
16438  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16439  }
16440  }
16441  }
16442  if(!InPrefDirFlag)
16443  {
16444  for(int x = 0; x < VectorCount; x++)
16445  {
16446  SearchVector.erase(SearchVector.end() - 1);
16447  }
16448  Utilities->CallLogPop(245);
16449  return(false);
16450  }
16451 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16452 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16453 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16455  {
16456  for(int x = 0; x < VectorCount; x++)
16457  {
16458  SearchVector.erase(SearchVector.end() - 1);
16459  }
16460  Utilities->CallLogPop(1690);
16461  return(false);
16462  }
16463 // check if found it
16464  if(SearchElement.TrackVectorPosition == RequiredPosition)
16465  {
16466 // need to ensure a signal/buffer/continuation
16467 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16468  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16469  {
16470  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16472  for(int x = 0; x < VectorCount; x++)
16473  {
16474  SearchVector.erase(SearchVector.end() - 1);
16475  }
16476  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16477  Utilities->CallLogPop(246);
16478  return(false);
16479  } // if((SearchElement.TrackType != SignalPost) &&.......
16480 //need to make sure it's in the right direction
16481  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16482  { //condition added at v2.16.1
16483  for(int x = 0; x < VectorCount; x++)
16484  {
16485  SearchVector.erase(SearchVector.end() - 1);
16486  }
16487  Utilities->CallLogPop(2627);
16488  return(false);
16489  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16490 
16491  if(AutoSigsFlag)
16492  {
16493  PrefDirElement1.AutoSignals = true;
16494  }
16495  PrefDirElement1.PrefDirRoute = true;
16497  {
16499  {
16500  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16502  }
16503  for(int x = 0; x < VectorCount; x++)
16504  {
16505  SearchVector.erase(SearchVector.end() - 1);
16506  }
16507  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16508  Utilities->CallLogPop(1928);
16509  return(false);
16510  }
16511  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16512  VectorCount++; // not really needed but include for tidyness
16513  TotalSearchCount++;
16514  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16515  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16516  for(int x = 0; x < VectorCount; x++)
16517  {
16518  SearchVector.erase(SearchVector.end() - 1);
16519  }
16520  Utilities->CallLogPop(2522);
16521  return(false);
16522  }
16523  Utilities->CallLogPop(247);
16524  return(true);
16525  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16526 
16527 // check if a buffer or continuation (end of search on this leg if not found by now)
16528  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16529  {
16530  for(int x = 0; x < VectorCount; x++)
16531  {
16532  SearchVector.erase(SearchVector.end() - 1);
16533  }
16534  Utilities->CallLogPop(248);
16535  return(false);
16536  }
16537 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16539  {
16540  for(int x = 0; x < VectorCount; x++)
16541  {
16542  SearchVector.erase(SearchVector.end() - 1);
16543  }
16544  Utilities->CallLogPop(1420);
16545  return(false);
16546  }
16547 //deal with failed points, added at v2.13.0
16548  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16549  {
16550  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16551  {
16552  SearchElement.XLinkPos = 1;
16553  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16554  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16555  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16556  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16557  }
16558  else
16559  {
16560  SearchElement.XLinkPos = 3;
16561  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16562  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16563  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16564  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16565  }
16566  }
16567  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16568  {
16569  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16570  {
16571  for(int x = 0; x < VectorCount; x++)
16572  {
16573  SearchVector.erase(SearchVector.end() - 1);
16574  }
16575  Utilities->CallLogPop(2514);
16576  return(false);
16577  }
16578  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16579  {
16580  for(int x = 0; x < VectorCount; x++)
16581  {
16582  SearchVector.erase(SearchVector.end() - 1);
16583  }
16584  Utilities->CallLogPop(2515);
16585  return(false);
16586  }
16587  }
16588 // check if reached a non-failed leading point
16589  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16590  {
16591 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16592  int SearchPos1 = SearchElement.Attribute + 1;
16593  int SearchPos2;
16594  if(SearchPos1 == 2)
16595  {
16596  SearchPos1++;
16597  }
16598  if(SearchPos1 == 1)
16599  {
16600  SearchPos2 = 3;
16601  }
16602  else
16603  {
16604  SearchPos2 = 1;
16605  }
16606  SearchElement.XLink = SearchElement.Link[SearchPos1];
16607  SearchElement.XLinkPos = SearchPos1;
16608  InPrefDirFlag = false;
16609  if(SearchElement.XLink == PrefDirElement1.XLink)
16610  {
16611  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16612  InPrefDirFlag = true;
16613  }
16614  else if(SearchElement.XLink == PrefDirElement2.XLink)
16615  {
16616  SearchElement = PrefDirElement2;
16617  InPrefDirFlag = true;
16618  }
16619 // push element with XLink set to position [SearchPos1] if on a PrefDir
16620  if(InPrefDirFlag)
16621  {
16622 // check for a fouled diagonal for leading point for XLinkPos == 1)
16623  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16624  {
16625  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16626  {
16627  for(int x = 0; x < VectorCount; x++)
16628  {
16629  SearchVector.erase(SearchVector.end() - 1);
16630  }
16631  Utilities->CallLogPop(249);
16632  return(false);
16633  }
16634  }
16635  if(AutoSigsFlag)
16636  {
16637  SearchElement.AutoSignals = true;
16638  }
16639  SearchElement.PrefDirRoute = true;
16640  SearchVector.push_back(SearchElement);
16641  VectorCount++;
16642  TotalSearchCount++;
16643 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16644  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16645  AutoSigsFlag, true))
16646  {
16648  {
16650  {
16651  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16653  }
16654  for(int x = 0; x < VectorCount; x++)
16655  {
16656  SearchVector.erase(SearchVector.end() - 1);
16657  }
16658  Utilities->CallLogPop(1929);
16659  return(false);
16660  }
16661  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16662  {
16663  for(int x = 0; x < VectorCount; x++)
16664  {
16665  SearchVector.erase(SearchVector.end() - 1);
16666  }
16667  Utilities->CallLogPop(2523);
16668  return(false);
16669  }
16670  Utilities->CallLogPop(250);
16671  return(true);
16672  }
16673  else
16674  {
16675 // remove leading point with XLinkPos [1]
16676  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16677  {
16678  SearchVector.erase(SearchVector.end() - 1);
16679  VectorCount--;
16680  }
16681  else
16682  {
16683  for(int x = 0; x < VectorCount; x++)
16684  {
16685  SearchVector.erase(SearchVector.end() - 1);
16686  }
16687  Utilities->CallLogPop(2626);
16688  return(false);
16689  }
16690  }
16691  }
16692 // XLink set to position [SearchPos2]
16693  SearchElement.XLink = SearchElement.Link[SearchPos2];
16694  SearchElement.XLinkPos = SearchPos2;
16695  if(SearchElement.XLink == PrefDirElement1.XLink)
16696  {
16697  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16698  }
16699  else if(SearchElement.XLink == PrefDirElement2.XLink)
16700  {
16701  SearchElement = PrefDirElement2;
16702  }
16703  else // failed to find a valid exit from the point
16704  {
16705  for(int x = 0; x < VectorCount; x++)
16706  {
16707  SearchVector.erase(SearchVector.end() - 1);
16708  }
16709  Utilities->CallLogPop(251);
16710  return(false);
16711  }
16712 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16713  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16714  {
16715  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16716  {
16717  for(int x = 0; x < VectorCount; x++)
16718  {
16719  SearchVector.erase(SearchVector.end() - 1);
16720  }
16721  Utilities->CallLogPop(252);
16722  return(false);
16723  }
16724  }
16725 // push element with XLink set to position [SearchPos2]
16726  if(AutoSigsFlag)
16727  {
16728  SearchElement.AutoSignals = true;
16729  }
16730  SearchElement.PrefDirRoute = true;
16731  SearchVector.push_back(SearchElement);
16732  VectorCount++;
16733  TotalSearchCount++;
16734 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16735  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16736  AutoSigsFlag, true))
16737  {
16739  {
16741  {
16742  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16744  }
16745  for(int x = 0; x < VectorCount; x++)
16746  {
16747  SearchVector.erase(SearchVector.end() - 1);
16748  }
16749  Utilities->CallLogPop(1930);
16750  return(false);
16751  }
16752  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16753  {
16754  for(int x = 0; x < VectorCount; x++)
16755  {
16756  SearchVector.erase(SearchVector.end() - 1);
16757  }
16758  Utilities->CallLogPop(2524);
16759  return(false);
16760  }
16761  Utilities->CallLogPop(1592);
16762  return(true);
16763  }
16764  else
16765  {
16766  for(int x = 0; x < VectorCount; x++)
16767  {
16768  SearchVector.erase(SearchVector.end() - 1);
16769  }
16770  Utilities->CallLogPop(253);
16771  return(false);
16772  }
16773  } // if leading point
16774 
16775 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16776  SearchElement = PrefDirElement1;
16777  if(AutoSigsFlag)
16778  {
16779  SearchElement.AutoSignals = true;
16780  }
16781  SearchElement.PrefDirRoute = true;
16782  SearchVector.push_back(SearchElement);
16783  VectorCount++;
16784  TotalSearchCount++;
16785  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16786  PrefDirElement = SearchElement;
16787  } // while(true)
16788 }
16789 
16790 // ---------------------------------------------------------------------------
16791 
16792 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16793 {
16794 /*
16795  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16796  and the new or extended route created from that. Hence action varies depending on whether
16797  it is a completely new route, or an extension of an existing route at the beginning or the end.
16798  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16799  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16800 
16801  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16802  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16803  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16804  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16805  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16806  is decremented;
16807  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16808  from the existing route, then enter the new route into the AllRoutesVector;
16809  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16810  then enter the new route into the AllRoutesVector.
16811 
16812  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16813  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16814  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16815  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16816  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16817  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16818  for the new route and return;
16819  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16820  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16821 
16822  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16823  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16824  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16825 
16826 */
16827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16828  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16829  if(SearchVector.size() < 1)
16830  {
16831  Utilities->CallLogPop(254);
16832  return;
16833  }
16835  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16836  {
16837  Utilities->CallLogPop(255);
16838  return;
16839  }
16840  TAllRoutes::TLockedRouteClass LockedRouteObject;
16841 
16843  unsigned int TruncatePrefDirPosition = 0;
16844 
16845  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16846 /* if have ReqPosRouteID:
16847  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16848  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16849  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16850  the existing route, then enter the new route into the AllRoutesVector
16851  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16852  then enter the new route into the AllRoutesVector
16853 */
16854  {
16857  {
16858  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16859  x++) // start at 1 as first element already in SearchVector
16860  {
16862  }
16863  // note that route numbers in map adjusted when ReqPos route cleared
16865  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16866  // set during ClearRouteDuringRouteBuildingAt
16868  {
16871  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16872  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16873  }
16874  }
16876  {
16878  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16879  }
16881  {
16882  SearchVector.pop_back();
16883  }
16884  }
16885  if(StartSelectionRouteID > -1)
16886 /* if have StartSelectionRouteID:
16887  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16888  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16889  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16890  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16891  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16892 */
16893  {
16895  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16896  {
16899  {
16900  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16901  for(unsigned int x = 0; x < SearchVector.size(); x++)
16902  {
16904  RouteNumber, GetFixedSearchElementAt(3, x));
16905  // find & store locked route truncate position in PrefDirVector for later use
16907  {
16908  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16909  {
16910  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16911  }
16912  }
16913  }
16915  {
16916  throw Exception("Error - failed to validate extended route for preferred route");
16917  }
16920  if(!AutoSigsFlag)
16921  {
16922  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16923  }
16924  // now add the reinstated locked route if required and set signals accordingly
16926  {
16927  LockedRouteObject.RouteNumber = RouteNumber;
16928  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16929  // now reset the signals for the locked route
16930  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16931  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16932  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16933  {
16934  // return all signals to red in route section to be truncated
16935  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16936  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16937  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16938  {
16939  TrackElement.Attribute = 0;
16940  Track->PlotSignal(10, TrackElement, Display);
16941  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16942  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16943  }
16944  }
16945  }
16946  AllRoutes->CheckMapAndRoutes(1); // test
16947  Utilities->CallLogPop(256);
16948  return;
16949  }
16951  {
16954  RouteElement.AutoSignals = true;
16955  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16956  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16957  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16958  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16959  }
16960  }
16961  else
16962  {
16964  }
16965 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16966 // AllRoutesVector hence nothing to do here
16967  }
16968  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16969  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16970  {
16971  throw Exception("Error - failed to validate single route for preferred route");
16972  }
16973  AllRoutes->StoreOneRoute(1, this);
16974  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16975  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16976  if(!AutoSigsFlag)
16977  {
16978  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16979  }
16980  AllRoutes->CheckMapAndRoutes(2); // test
16981  Utilities->CallLogPop(257);
16982 }
16983 
16984 // ---------------------------------------------------------------------------
16985 
16986 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16987 {
16988 /*
16989  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16990  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16991  & ensure signal/buffers/continuation.
16992  Note that can't select ConsecSignalsRoute for non-preferred routes.
16993  Check if train on element & disallow.
16994  Set default values for retained parameters:-
16995  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16996  StartSelectionRouteID = route that selection starts in if there is one;
16997 
16998  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16999  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
17000  validity. This is just for safety reasons, the PrefDir values aren't used.
17001  StartElement1 & 2 are set to these PrefDirelements.
17002 
17003  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
17004 
17005  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
17006  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
17007  blank StartElement2 (only want to use the route element), then return true.
17008  Check if adjacent to start or end of an existing route & disallow if so.
17009  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
17010  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
17011  SetRemainingSearchVectorValues().
17012  Finally add the required element to the SearchVector & return true.
17013 
17014 */
17015  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
17016  AnsiString(VLoc) + "," + AnsiString((short)Callon));
17017  ClearRoute();
17018  int TrackVectorPosition;
17019  TTrackElement TrackElement;
17020  TPrefDirElement FirstElement, LastElement;
17021 
17022  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
17023  {
17024  Utilities->CallLogPop(258);
17025  return(false);
17026  }
17027  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17028  {
17029  if(!Callon)
17030  {
17031  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
17032  }
17033 // makes later adjacent route checks too complicated
17034  Utilities->CallLogPop(259);
17035  return(false);
17036  }
17037  if(Track->IsLCAtHV(21, HLoc, VLoc))
17038  {
17039  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
17040  Utilities->CallLogPop(1910);
17041  return(false);
17042  }
17043 // check if selected a train & disallow if so
17044  if(TrackElement.TrainIDOnElement > -1)
17045  {
17046  if(!Callon)
17047  {
17048  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
17049  }
17050  Utilities->CallLogPop(260);
17051  return(false);
17052  }
17053 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
17054  TPrefDirElement PrefDirElement;
17055  int LockedVectorNumber;
17056 
17057  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
17058  {
17059  if(!Callon)
17060  {
17061  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
17062  }
17063  Utilities->CallLogPop(261);
17064  return(false);
17065  }
17066  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
17067  {
17068  if(!Callon)
17069  {
17070  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
17071  }
17072  Utilities->CallLogPop(262);
17073  return(false);
17074  }
17076 // AdjacentStartRouteNumber = -1;
17077  StartRoutePosition = TrackVectorPosition;
17078 // StartRouteSelectPosition = TrackVectorPosition;
17079 
17080  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17081  TPrefDirElement PrefDirElement2(TrackElement);
17082 
17083  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
17084  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
17085  TPrefDirElement BlankElement;
17086 
17087  PrefDirElement1.ELinkPos = 0;
17088  PrefDirElement1.XLinkPos = 1;
17089  PrefDirElement1.ELink = PrefDirElement1.Link[0];
17090  PrefDirElement1.XLink = PrefDirElement1.Link[1];
17091  if(!(PrefDirElement1.EntryExitNumber()))
17092  {
17093  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
17094  // no need for bridge check as bridge selections not allowed
17095  }
17096  PrefDirElement1.CheckCount = 9;
17097  PrefDirElement2.ELinkPos = 1;
17098  PrefDirElement2.XLinkPos = 0;
17099  PrefDirElement2.ELink = PrefDirElement2.Link[1];
17100  PrefDirElement2.XLink = PrefDirElement2.Link[0];
17101  if(!(PrefDirElement2.EntryExitNumber()))
17102  {
17103  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
17104  }
17105  PrefDirElement2.CheckCount = 9; // both now set
17106 
17107 // set StartElements to the above PrefDirElements
17108  StartElement1 = PrefDirElement1;
17109  StartElement2 = PrefDirElement2;
17110 
17111 // no PrefDir check needed as doesn't need to be in a PrefDir
17112 
17113 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
17115  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17116 
17117  if(RoutePair.first > -1)
17118  {
17119  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
17120  {
17121  if(!Callon)
17122  {
17123  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
17124  }
17125  Utilities->CallLogPop(263);
17126  return(false);
17127  }
17128  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
17129  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
17130  {
17131  if(!Callon)
17132  {
17133  TrainController->StopTTClockMessage(39, "No forward connection from this position");
17134  }
17135  Utilities->CallLogPop(264);
17136  return(false);
17137  }
17138  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
17139  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
17140  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17141  {
17142 // if(!Callon) //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
17143 // {
17144 // TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
17145 // }
17146 // Utilities->CallLogPop(265);
17147 // return(false);
17148  }
17149  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
17151  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
17152  StartElement2 = BlankElement; // only use the route element
17154  Utilities->CallLogPop(266);
17155  return(true); // all retained values set
17156  }
17157 
17158  else // selection not in an existing route
17159  {
17160 // check if it's adjacent to start of an an existing route,
17161  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17162  {
17163  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
17164  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
17165  {
17166  if(!Callon)
17167  {
17168  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
17169  }
17170  Utilities->CallLogPop(267);
17171  return(false);
17172  }
17173  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
17174  {
17175  if(!Callon)
17176  {
17177  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
17178  }
17179  Utilities->CallLogPop(268);
17180  return(false);
17181  }
17182  }
17183 // check if it's adjacent to end of an an existing route,
17184  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17185  {
17187  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
17188  {
17189  if(!Callon)
17190  {
17191  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
17192  }
17193  Utilities->CallLogPop(269);
17194  return(false);
17195  }
17196  }
17197  // not in a route or adjacent to start or end of a route
17198  // in this case reset all variable values to -1 & CheckCount to 4
17199  StartElement1.ELink = -1;
17200  StartElement1.ELinkPos = -1;
17201  StartElement1.XLink = -1;
17202  StartElement1.XLinkPos = -1;
17203  StartElement1.EXNumber = -1;
17204  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
17205  StartElement2 = BlankElement;
17206  SearchVector.push_back(StartElement1);
17207  Utilities->CallLogPop(270);
17208  return(true);
17209  }
17210 }
17211 
17212 // ---------------------------------------------------------------------------
17213 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
17214 
17215 /*
17216  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
17217 
17218  Declare the following integers:-
17219  EndPosition - TrackVectorPosition for the selection;
17220  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
17221  Check if selection is a valid track element and set EndPosition.
17222  Cancel if select original start element, then check that not points, bridge or crossover.
17223  Check & fail if a train is present at the selection.
17224  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
17225  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
17226  No check needed for selection in EveryPrefDir.
17227  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
17228  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
17229  as don't need it if in a route.
17230  Check if selection adj to start or end of a route and disallow.
17231  Fail if select same route as starting route, though should already have failed earlier if this is so.
17232 
17233  If there's a StartSelectionRouteID then StartElement1 will be set to
17234  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
17235  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
17236  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
17237  to add the new route to the AllRoutesVectorPtr.
17238  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
17239  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
17240  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
17241  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
17242  the search vector values and return.
17243  If not returned yet then have failed to find the required element so return false with no message.
17244 
17245 */
17246 
17247 {
17248 // get EndPosition
17249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
17250  AnsiString(VLoc));
17251  int EndPosition;
17252  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
17253 
17254  TotalSearchCount = 0;
17255  ReqPosRouteID = IDInt(-1); // for not used
17256  TTrackElement TrackElement;
17257  TPrefDirElement BlankElement;
17259 
17260  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
17261  {
17262  Utilities->CallLogPop(271);
17263  return(false);
17264  }
17265 // EndPosition = EndSelectPosition;
17266 // cancel selection if on original start element
17267  if(EndPosition == StartRoutePosition)
17268  {
17269  Utilities->CallLogPop(272);
17270  return(false);
17271  }
17272  if(Track->IsLCAtHV(22, HLoc, VLoc))
17273  {
17274  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
17275  Utilities->CallLogPop(1911);
17276  return(false);
17277  }
17278  if((TrackElement.TrackType == Points) && !Callon)
17279  {
17280  if(!Callon)
17281  {
17282  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
17283  }
17284 // makes later adjacent route checks too complicated
17285  Utilities->CallLogPop(273);
17286  return(false);
17287  }
17288  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17289  {
17290  if(!Callon)
17291  {
17292  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
17293  }
17294 // makes later adjacent route checks too complicated
17295  Utilities->CallLogPop(1861);
17296  return(false);
17297  }
17298 // check if train on element
17299  if(TrackElement.TrainIDOnElement > -1)
17300  {
17301  if(!Callon)
17302  {
17303  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17304  }
17305  Utilities->CallLogPop(274);
17306  return(false);
17307  }
17308 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17309 // check passed)
17310  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17311  TPrefDirElement EndElement2(TrackElement);
17312 
17313  EndElement1.TrackVectorPosition = EndPosition;
17314  EndElement2.TrackVectorPosition = EndPosition;
17315  EndElement1.ELinkPos = 0;
17316  EndElement1.XLinkPos = 1;
17317  EndElement1.ELink = EndElement1.Link[0];
17318  EndElement1.XLink = EndElement1.Link[1];
17319  if(!(EndElement1.EntryExitNumber()))
17320  {
17321  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17322  }
17323  EndElement1.CheckCount = 9;
17324  EndElement2.ELinkPos = 1;
17325  EndElement2.XLinkPos = 0;
17326  EndElement2.ELink = EndElement2.Link[1];
17327  EndElement2.XLink = EndElement2.Link[0];
17328  if(!(EndElement2.EntryExitNumber()))
17329  {
17330  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17331  }
17332  EndElement2.CheckCount = 9; // both now set
17333 
17334 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17335 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17336 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17337 
17338  if(EndElement1.HLoc >= StartElement1.HLoc)
17339  {
17341  SearchLimitHighH = EndElement1.HLoc + 15;
17342  }
17343  else
17344  {
17345  SearchLimitLowH = EndElement1.HLoc - 15;
17347  }
17348  if(EndElement1.VLoc >= StartElement1.VLoc)
17349  {
17351  SearchLimitHighV = EndElement1.VLoc + 15;
17352  }
17353  else
17354  {
17355  SearchLimitLowV = EndElement1.VLoc - 15;
17357  }
17358 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17359  check & TotalSearchCounts check
17360  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17361  {
17362  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17363  Utilities->CallLogPop(1694);
17364  return false;
17365  }
17366 */
17367 // don't need EveryPrefDir check for NonPreferredRoute
17368 
17369 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17370 // bool InRoute = false;
17372  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17373 
17374  if(RoutePair.first > -1)
17375  {
17376  if(RoutePair.second != 0) // not first element in existing route so no good
17377  {
17378  if(!Callon)
17379  {
17380  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17381  }
17382  Utilities->CallLogPop(275);
17383  return(false);
17384  }
17385  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17386 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17387  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17388  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17389  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17390  {
17391  if(!Callon)
17392  {
17393  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17394  }
17395  Utilities->CallLogPop(276);
17396  return(false);
17397  }
17398  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17399  EndElement2 = BlankElement; // only need the route element
17400  EndPosition = EndElement1.TrackVectorPosition;
17401  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17402  }
17403 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17404  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17405  {
17406  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17407  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17408 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17409 // && (AdjPosition != StartRoutePosition))
17410  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17411  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17412  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17413  {
17414  if(!Callon)
17415  {
17416  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17417  }
17418  Utilities->CallLogPop(277);
17419  return(false);
17420  }
17421 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17422 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17423  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17424  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17425  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17426  (AdjPosition != StartRoutePosition))
17427  {
17428  if(!Callon)
17429  {
17430  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17431  }
17432  Utilities->CallLogPop(278);
17433  return(false);
17434  }
17435 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17437  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17438  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17439  {
17440  if(!Callon)
17441  {
17442  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17443  }
17444  Utilities->CallLogPop(279);
17445  return(false);
17446  }
17447  }
17448 
17449 // check for same route as start element
17451  {
17452  if(!Callon)
17453  {
17454  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17455  }
17456  Utilities->CallLogPop(280);
17457  return(false);
17458  }
17459 // check for a looping route
17460  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17461  {
17463  {
17464  if(!Callon)
17465  {
17466  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17467  }
17468  Utilities->CallLogPop(1845);
17469  return(false);
17470  }
17471  }
17472 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17473 // so search from this element.
17474 
17475  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17476 
17477  if(StartSelectionRouteID > -1)
17478  {
17479  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17480  {
17482  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17483  {
17484  if(NewFailedPointsTVPos > -1)
17485  {
17486  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17487  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17488  " failed during route setting.");
17489  Utilities->CallLogPop(2504);
17490  return(false);
17491  }
17492  PointsChanged = true;
17493  }
17494  Utilities->CallLogPop(281);
17495  return(true);
17496  }
17497  else
17498  {
17499  if(!Callon && !Track->SuppressRouteFailMessage)
17500  {
17502  }
17503  Utilities->CallLogPop(282);
17504  return(false);
17505  }
17506  }
17507  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17508  // search on the 2 ways out of the element, which has to be a 2-ended element
17509  {
17510 // check if selection adjacent to start element and if so use that
17511  if(SearchVector.at(0).Conn[0] == EndPosition)
17512  {
17513  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17514  {
17516  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17517  {
17518  if(NewFailedPointsTVPos > -1)
17519  {
17520  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17521  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17522  " failed during route setting.");
17523  Utilities->CallLogPop(2506);
17524  return(false);
17525  }
17526  PointsChanged = true;
17527  }
17528  Utilities->CallLogPop(283);
17529  return(true);
17530  }
17531  else
17532  {
17533  if(!Callon && !Track->SuppressRouteFailMessage)
17534  {
17536  }
17537  Utilities->CallLogPop(284);
17538  return(false);
17539  }
17540  }
17541  else if(SearchVector.at(0).Conn[1] == EndPosition)
17542  {
17543  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17544  {
17546  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17547  {
17548  if(NewFailedPointsTVPos > -1)
17549  {
17550  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17551  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17552  " failed during route setting.");
17553  Utilities->CallLogPop(2508);
17554  return(false);
17555  }
17556  PointsChanged = true;
17557  }
17558  Utilities->CallLogPop(285);
17559  return(true);
17560  }
17561  else
17562  {
17563  if(!Callon && !Track->SuppressRouteFailMessage)
17564  {
17566  }
17567  Utilities->CallLogPop(286);
17568  return(false);
17569  }
17570  }
17571  // now start off in the best direction
17572  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17573 
17574  if(SearchVector.at(0).Config[BestPos] != End)
17575  {
17576  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17577  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17578  {
17580  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17581  {
17582  if(NewFailedPointsTVPos > -1)
17583  {
17584  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17585  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17586  " failed during route setting.");
17587  Utilities->CallLogPop(2510);
17588  return(false);
17589  }
17590  PointsChanged = true;
17591  }
17592  Utilities->CallLogPop(287);
17593  return(true);
17594  }
17595  }
17596  if(SearchVector.at(0).Config[1 - BestPos] != End)
17597  {
17598  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17599  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17600  {
17602  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17603  {
17604  if(NewFailedPointsTVPos > -1)
17605  {
17606  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17607  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17608  " failed during route setting.");
17609  Utilities->CallLogPop(2512);
17610  return(false);
17611  }
17612  PointsChanged = true;
17613  }
17614  Utilities->CallLogPop(288);
17615  return(true);
17616  }
17617  }
17618  }
17619  if(!Callon && !Track->SuppressRouteFailMessage)
17620  {
17622  }
17623  Utilities->CallLogPop(289);
17624  return(false);
17625 }
17626 
17627 // ---------------------------------------------------------------------------
17628 
17629 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17630 /*
17631  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17632  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17633  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17634  Keep a count of entries in SearchVector during the current function call, so that this number can be
17635  erased for an unproductive branch search.
17636  First check (within the loop) whether XLink leads to an End & return false if so.
17637  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17638  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17639  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17640  train on element (unless a bridge & train on different track), or if element
17641  fouls an existing diagonal route (except if element is a leading point - these checked later).
17642  Then check if found required element. If so save it & return true.
17643  If not the required element check if buffer or continuation, & if so erase all searchvector
17644  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17645  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17646  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17647  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17648  When return true have 8 items from CheckCount established, only waiting for EXNumber
17649 */
17650 {
17651  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17652  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17653  int VectorCount = 0;
17654 
17655 // check for a fouled diagonal for first element. Added for v1.3.2
17656  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17657  (CurrentTrackElement.Link[XLinkPos] == 9))
17658  {
17659  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17660  {
17661  for(int x = 0; x < VectorCount; x++)
17662  {
17663  SearchVector.erase(SearchVector.end() - 1);
17664  }
17665  Utilities->CallLogPop(2044);
17666  return(false);
17667  }
17668  }
17669  while(true)
17670  {
17671  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17672  {
17673  for(int x = 0; x < VectorCount; x++)
17674  {
17675  SearchVector.erase(SearchVector.end() - 1);
17676  }
17677  Utilities->CallLogPop(1927);
17678  return(false);
17679  }
17680  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17681  {
17682  for(int x = 0; x < VectorCount; x++)
17683  {
17684  SearchVector.erase(SearchVector.end() - 1);
17685  }
17686  Utilities->CallLogPop(290);
17687  return(false);
17688  }
17689  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17690  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17691  TPrefDirElement SearchElement(NextTrackElement);
17692  SearchElement.TrackVectorPosition = NextPosition;
17693  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17694  SearchElement.ELinkPos = NextELinkPos;
17695  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17696  int NextXLinkPos;
17697  if(SearchElement.ELinkPos == 0)
17698  {
17699  NextXLinkPos = 1;
17700  }
17701  if(SearchElement.ELinkPos == 1)
17702  {
17703  NextXLinkPos = 0;
17704  }
17705  if(SearchElement.ELinkPos == 2)
17706  {
17707  NextXLinkPos = 3;
17708  }
17709  if(SearchElement.ELinkPos == 3)
17710  {
17711  NextXLinkPos = 2;
17712  }
17713  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17714  {
17715  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17716  // but may be buffers, continuation or gap
17717  SearchElement.XLinkPos = NextXLinkPos;
17718  }
17719 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17720 // can't set XLink or XLinkPos yet if the element is a leading point.
17721 
17722 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17723  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17724  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17725  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17726 
17727  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17728 */
17729  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17730  {
17731  for(unsigned int x = 0; x < SearchVector.size(); x++)
17732  {
17733  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17734  {
17735  for(int x = 0; x < VectorCount; x++)
17736  {
17737  SearchVector.erase(SearchVector.end() - 1);
17738  }
17739  Utilities->CallLogPop(2655);
17740  return(false);
17741  }
17742  }
17743  }
17744  else if(SearchElement.TrackType == Bridge)
17745  {
17746  for(unsigned int x = 0; x < SearchVector.size(); x++)
17747  {
17748  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17749  (SearchElement.ELink == SearchVector.at(x).ELink))
17750  {
17751  for(int x = 0; x < VectorCount; x++)
17752  {
17753  SearchVector.erase(SearchVector.end() - 1);
17754  }
17755  Utilities->CallLogPop(2656);
17756  return(false);
17757  }
17758  }
17759  }
17760 
17761 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17762  TAllRoutes::TRouteElementPair SecondPair;
17764  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17765  if(RoutePair.first > -1)
17766  {
17767  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17768  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17769  RoutePair.second).ELinkPos)))
17770  {
17771  // still OK if start of an expected route
17772  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17773  {
17774  for(int x = 0; x < VectorCount; x++)
17775  {
17776  SearchVector.erase(SearchVector.end() - 1);
17777  }
17778  Utilities->CallLogPop(292);
17779  return(false); // only allow for start of an expected route
17780  }
17781  }
17782  }
17783  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17784  {
17785  // OK if it's a bridge & routes on different tracks
17786  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17787  SecondPair.second).ELinkPos)))
17788  {
17789  // still OK if start of an expected route
17790  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17791  {
17792  for(int x = 0; x < VectorCount; x++)
17793  {
17794  SearchVector.erase(SearchVector.end() - 1);
17795  }
17796  Utilities->CallLogPop(293);
17797  return(false); // only allow for start of an expected route
17798  }
17799  }
17800  }
17801 // check if a train on element, unless a bridge & train on different track
17802 // OK of same train as start element - no, drop this
17803 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17804  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17805  {
17806  for(int x = 0; x < VectorCount; x++)
17807  {
17808  SearchVector.erase(SearchVector.end() - 1);
17809  }
17810  Utilities->CallLogPop(294);
17811  return(false);
17812  }
17813  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17814  {
17815  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17816  {
17817  for(int x = 0; x < VectorCount; x++)
17818  {
17819  SearchVector.erase(SearchVector.end() - 1);
17820  }
17821  Utilities->CallLogPop(295);
17822  return(false);
17823  }
17824  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17825  {
17826  for(int x = 0; x < VectorCount; x++)
17827  {
17828  SearchVector.erase(SearchVector.end() - 1);
17829  }
17830  Utilities->CallLogPop(296);
17831  return(false);
17832  }
17833  }
17834 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17835  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17836  {
17837  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17838  {
17839  for(int x = 0; x < VectorCount; x++)
17840  {
17841  SearchVector.erase(SearchVector.end() - 1);
17842  }
17843  Utilities->CallLogPop(297);
17844  return(false);
17845  }
17846  }
17847 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17848 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17849 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17851  {
17852  for(int x = 0; x < VectorCount; x++)
17853  {
17854  SearchVector.erase(SearchVector.end() - 1);
17855  }
17856  Utilities->CallLogPop(1689);
17857  return(false);
17858  }
17859 // check if found it
17860  if(SearchElement.TrackVectorPosition == RequiredPosition)
17861  {
17862  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17863  {
17864  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17865  {
17866  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17867  }
17868  else
17869  {
17870  SearchElement.XLinkPos = 1;
17871  }
17872 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17873  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17874  }
17875  SearchVector.push_back(SearchElement);
17876  VectorCount++; // not really needed but include for tidyness
17877  TotalSearchCount++;
17878  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17879  {
17880  for(int x = 0; x < VectorCount; x++)
17881  {
17882  SearchVector.erase(SearchVector.end() - 1);
17883  }
17884  Utilities->CallLogPop(2525);
17885  return(false);
17886  }
17887  Utilities->CallLogPop(298);
17888  return(true);
17889  }
17890 // Not the required element - check if a buffer or continuation
17891  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17892  {
17893  for(int x = 0; x < VectorCount; x++)
17894  {
17895  SearchVector.erase(SearchVector.end() - 1);
17896  }
17897  Utilities->CallLogPop(299);
17898  return(false);
17899  }
17900 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17902  {
17903  for(int x = 0; x < VectorCount; x++)
17904  {
17905  SearchVector.erase(SearchVector.end() - 1);
17906  }
17907  Utilities->CallLogPop(1421);
17908  return(false);
17909  }
17910 //deal with failed points, added at v2.13.0
17911  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17912  {
17913  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17914  {
17915  SearchElement.XLinkPos = 1;
17916  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17917  }
17918  else
17919  {
17920  SearchElement.XLinkPos = 3;
17921  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17922  }
17923  }
17924  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17925  {
17926  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17927  {
17928  for(int x = 0; x < VectorCount; x++)
17929  {
17930  SearchVector.erase(SearchVector.end() - 1);
17931  }
17932  Utilities->CallLogPop(2533);
17933  return(false);
17934  }
17935  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17936  {
17937  for(int x = 0; x < VectorCount; x++)
17938  {
17939  SearchVector.erase(SearchVector.end() - 1);
17940  }
17941  Utilities->CallLogPop(2534);
17942  return(false);
17943  }
17944  }
17945 
17946 // check if reached a non-failed leading point
17947  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17948  { //added !Failed condition at v2.13.0 to exclude failed points
17949 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17950  int SearchPos1 = SearchElement.Attribute + 1;
17951  int SearchPos2;
17952  if(SearchPos1 == 2)
17953  {
17954  SearchPos1++;
17955  }
17956  if(SearchPos1 == 1)
17957  {
17958  SearchPos2 = 3;
17959  }
17960  else
17961  {
17962  SearchPos2 = 1;
17963  }
17964 // push element with XLink set to position [SearchPos1]
17965  SearchElement.XLink = SearchElement.Link[SearchPos1];
17966  SearchElement.XLinkPos = SearchPos1;
17967 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17968  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17969  {
17970  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17971  {
17972  for(int x = 0; x < VectorCount; x++)
17973  {
17974  SearchVector.erase(SearchVector.end() - 1);
17975  }
17976  Utilities->CallLogPop(300);
17977  return(false);
17978  }
17979  }
17980  SearchVector.push_back(SearchElement);
17981  VectorCount++;
17982  TotalSearchCount++;
17983 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17984 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17985 // recursive search as has to be a TTrackElement for non-preferred route searches
17986  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17987  {
17988  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17989  {
17990  for(int x = 0; x < VectorCount; x++)
17991  {
17992  SearchVector.erase(SearchVector.end() - 1);
17993  }
17994  Utilities->CallLogPop(2526);
17995  return(false);
17996  }
17997  Utilities->CallLogPop(301);
17998  return(true);
17999  }
18000  else
18001  {
18002 // remove leading point with XLinkPos [SearchPos1]
18003  SearchVector.erase(SearchVector.end() - 1);
18004  VectorCount--;
18005 // push element with XLink set to position [SearchPos2]
18006  SearchElement.XLink = SearchElement.Link[SearchPos2];
18007  SearchElement.XLinkPos = SearchPos2;
18008 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
18009  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
18010  {
18011  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
18012  {
18013  for(int x = 0; x < VectorCount; x++)
18014  {
18015  SearchVector.erase(SearchVector.end() - 1);
18016  }
18017  Utilities->CallLogPop(302);
18018  return(false);
18019  }
18020  }
18021  SearchVector.push_back(SearchElement);
18022  VectorCount++;
18023  TotalSearchCount++;
18024 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
18025  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
18026  {
18027  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
18028  {
18029  for(int x = 0; x < VectorCount; x++)
18030  {
18031  SearchVector.erase(SearchVector.end() - 1);
18032  }
18033  Utilities->CallLogPop(2527);
18034  return(false);
18035  }
18036  Utilities->CallLogPop(303);
18037  return(true);
18038  }
18039  else
18040  {
18041  for(int x = 0; x < VectorCount; x++)
18042  {
18043  SearchVector.erase(SearchVector.end() - 1);
18044  }
18045  Utilities->CallLogPop(304);
18046  return(false);
18047  }
18048  }
18049  } // if leading point
18050 
18051 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
18052 // ready for next element on route
18053  SearchVector.push_back(SearchElement);
18054  VectorCount++;
18055  TotalSearchCount++;
18056  CurrentTrackElement = SearchElement;
18057  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
18058  } // while(true)
18059 }
18060 
18061 // ---------------------------------------------------------------------------
18062 
18064 
18065 /*
18066  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
18067  having all values set (since not necessarily on PrefDirs).
18068  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
18069  (if it was the start), so these are checked first and set if necessary. All elements now have
18070  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
18071  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
18072  to set the route colour and direction graphics.
18073 */
18074 
18075 {
18076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
18077  if(SearchVector.size() == 0)
18078  {
18079  throw Exception("Error, SearchVector empty");
18080  }
18081 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
18082 // hence need to examine and update it if necessary
18083  TPrefDirElement SecondElement;
18084 
18085  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
18086  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
18087  // need above check or SecondElement will fail
18088  {
18089  SecondElement = SearchVector.at(1);
18090  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
18091  for(int x = 0; x < 4; x++)
18092  {
18093  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
18094  {
18095  if(SearchVector.at(0).XLink == -1) // i.e. not set
18096  {
18097  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
18098  SearchVector.at(0).XLinkPos = x;
18099  }
18100  int ELinkPos;
18101  if(SearchVector.at(0).XLinkPos == 0)
18102  {
18103  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
18104  }
18105  // linked to 1st searchvector element, & if XLink was set then x may not correspond
18106  if(SearchVector.at(0).XLinkPos == 1)
18107  {
18108  ELinkPos = 0;
18109  }
18110  if(SearchVector.at(0).XLinkPos == 2)
18111  {
18112  ELinkPos = 3;
18113  }
18114  if(SearchVector.at(0).XLinkPos == 3)
18115  {
18116  ELinkPos = 2;
18117  }
18118  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
18119  {
18120  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
18121  SearchVector.at(0).ELinkPos = ELinkPos;
18122  }
18123  break; // no point going any further
18124  }
18125  }
18126  }
18127  for(unsigned int x = 0; x < SearchVector.size(); x++)
18128  {
18129  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
18130 // set EXNumber
18131  if(!(SearchVector.at(x).EntryExitNumber()))
18132  {
18133  throw Exception("Error in EntryExitNumber 3");
18134  }
18135  SearchVector.at(x).CheckCount++;
18136 // all values now incorporated
18137  }
18138 
18139  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
18140 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
18141 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
18142  Utilities->CallLogPop(305);
18143 }
18144 
18145 // ---------------------------------------------------------------------------
18146 
18148 
18149 /*
18150  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
18151  AutoSigsRoute.
18152  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
18153  beginning or the end.
18154  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
18155  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
18156  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
18157  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
18158  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
18159  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
18160  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
18161 
18162  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
18163  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
18164  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
18165  route at the start.
18166 
18167  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
18168  for the new route and return.
18169 */
18170 
18171 {
18172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
18173  AnsiString(ReqPosRouteID.GetInt()));
18174  if(SearchVector.size() < 1)
18175  {
18176  Utilities->CallLogPop(306);
18177  return;
18178  }
18179  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
18180  if(!ValidatePrefDir(6))
18181  {
18182  Utilities->CallLogPop(307);
18183  return;
18184  }
18185  TAllRoutes::TLockedRouteClass LockedRouteObject;
18186 
18188  unsigned int TruncatePrefDirPosition = 0;
18189 
18190  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
18191 /* if have ReqPosRouteID:
18192  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
18193  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
18194  then enter the new route into the AllRoutesVector
18195 */
18196  {
18198  {
18199  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
18200  x++) // start at 1 as first element already in SearchVector
18201  {
18203  }
18204  // note that route numbers in map adjusted when ReqPos route cleared
18206  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
18207  // set during ClearRouteDuringRouteBuildingAt)
18209  {
18212  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
18213  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
18214  }
18215  }
18217  {
18218  SearchVector.pop_back();
18219  }
18220  }
18221  if(StartSelectionRouteID > -1)
18222 /* if have StartSelectionRouteID:
18223  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
18224  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18225 */
18226  {
18228  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
18229  {
18231  {
18232  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
18233  for(unsigned int x = 0; x < SearchVector.size(); x++)
18234  {
18236  RouteNumber, GetFixedSearchElementAt(7, x));
18237  // find & store locked route truncate position in PrefDirVector for later use
18239  {
18240  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
18241  {
18242  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
18243  }
18244  }
18245  }
18247  {
18248  throw Exception("Failed to validate extended route for nonpreferred route");
18249  }
18252  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
18253  // now add the reinstated locked route if required and set signals accordingly
18254  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
18255  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
18256  // that I haven't thought of
18258  {
18259  LockedRouteObject.RouteNumber = RouteNumber;
18260  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
18261  // now reset the signals for the locked route
18262  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
18263  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
18264  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
18265  {
18266  // return all signals to red in route section to be truncated
18267  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
18268  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
18269  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18270  {
18271  TrackElement.Attribute = 0;
18272  Track->PlotSignal(11, TrackElement, Display);
18273  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18274  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18275  }
18276  }
18277  }
18278  AllRoutes->CheckMapAndRoutes(3); // test
18279  Utilities->CallLogPop(308);
18280  return;
18281  }
18282  }
18283  else
18284  {
18286  }
18287 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18288 // hence nothing to do here
18289  }
18290  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
18291  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
18292  {
18293  throw Exception("Failed to validate single route for nonpreferred route");
18294  }
18295  AllRoutes->StoreOneRoute(2, this);
18296  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
18297  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18298  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18299  AllRoutes->CheckMapAndRoutes(4); // test
18300  Utilities->CallLogPop(309);
18301 }
18302 
18303 // ---------------------------------------------------------------------------
18304 
18305 void TOneRoute::SetRoutePoints(int Caller) const
18306 /*
18307  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18308  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18309  when they were created.
18310 */
18311 {
18312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18313  if(!PrefDirVector.empty())
18314  {
18315  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18316  {
18317  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18318  {
18319  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18320  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18321  }
18322  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18323  {
18324  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18325  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18326  }
18327  }
18328  }
18329  Utilities->CallLogPop(327);
18330 }
18331 
18332 // ---------------------------------------------------------------------------
18333 
18334 void TOneRoute::SetRouteSignals(int Caller) const
18335 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18336 
18337 {
18338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18339  if(!PrefDirVector.empty())
18340  {
18341  int RouteNumber;
18342  int Attribute = 0;
18343  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18344  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18345  if(RouteType != TAllRoutes::NoRoute)
18346  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18347  {
18348  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18349  }
18350  }
18351  Utilities->CallLogPop(1720);
18352 }
18353 
18354 // ---------------------------------------------------------------------------
18355 
18356 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18357 {
18358  //true if at any point in SearchVector points have to be changed,
18359  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18360  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18361  NewFailedPointsTVPos = -1; //default value for no new failure
18362  bool PointsChanged = false;
18363  if(!SearchVector.empty())
18364  {
18365  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18366  {
18367  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18368  //check for an existing failed point where needs to change to make the route
18369  int Attr = TE.Attribute;
18370  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18371  {
18372  if(Attr == 1) //currently set to diverge
18373  {
18374  //here add new failure possibility at v2.13.0
18375  if(Utilities->FailureMode != FNil)
18376  {
18377  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18378  {
18380  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18381  IFE.TVPos = NewFailedPointsTVPos;
18382  TE.Failed = true;
18383  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18385  TE.SpeedLimit01 = 10; //values while failed
18386  TE.SpeedLimit23 = 10;
18387  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18388  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18389  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18390  //set repair time, random value in minutes between 10 and 179
18391  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18392  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18393  IFE.RepairTime = RepairTime;
18395  Track->FailedPointsVector.push_back(IFE);
18396  Utilities->CallLogPop(1717);
18397  return(true); //return so only allow one failure per route
18398  }
18399  }
18400  PointsChanged = true; //this is used for setting the flash time
18401  }
18402  }
18403  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18404  {
18405  if(Attr == 0) //currently set to go straight
18406  {
18407  //here add failure possibility at v2.13.0
18408  if(Utilities->FailureMode != FNil)
18409  {
18410  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18411  {
18413  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18414  IFE.TVPos = NewFailedPointsTVPos;
18415  TE.Failed= true;
18416  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18418  TE.SpeedLimit01 = 10; //values while failed
18419  TE.SpeedLimit23 = 10;
18420  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18421  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18422  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18423  //set repair time, random value in minutes between 10 and 179
18424  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18425  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18426  IFE.RepairTime = RepairTime;
18428  Track->FailedPointsVector.push_back(IFE);
18429  Utilities->CallLogPop(1718);
18430  return(true); //only allow one failure per route
18431  }
18432  }
18433  PointsChanged = true;
18434  }
18435  }
18436  }
18437  }
18438  Utilities->CallLogPop(1719);
18439  return(PointsChanged);
18440 }
18441 
18442 // ---------------------------------------------------------------------------
18443 
18444 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18445 /* //added StartPos at v2.17.0 so it starts in the current route
18446 
18447  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18448 
18449  Works forward through the route from & including StartPos until finds:-
18450  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18451  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18452  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18453  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18454  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18455  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18456  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18457  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18458  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18459 */
18460 {
18461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18462  Attribute = 0;
18463  NextForwardLinkedRouteNumber = -1;
18464  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18465  {
18466  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18467  if(PrefDirVector.at(x).TrackType == Bridge)
18468  {
18469  if(PrefDirVector.at(x).XLinkPos < 2)
18470  {
18471  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18472  }
18473  else
18474  {
18475  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18476  }
18477  }
18478  if(TrainID != -1)
18479  {
18480  Utilities->CallLogPop(328); //attribute still 0
18481  return(true);
18482  }
18483  if(PrefDirVector.at(x).TrackType == Buffers)
18484  {
18485  Attribute = 1;
18486  Utilities->CallLogPop(329);
18487  return(true);
18488  }
18489  if(PrefDirVector.at(x).TrackType == Continuation)
18490  {
18491  Attribute = 3;
18492  Utilities->CallLogPop(330);
18493  return(true);
18494  }
18495  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18496  {
18497  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18498  {
18499  Attribute = 0;
18500  Utilities->CallLogPop(1950);
18501  return(true);
18502  }
18503  }
18504  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18505  {
18506  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18507  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18508  {
18509  Attribute++;
18510  }
18511  if(Attribute > 3)
18512  {
18513  Attribute = 3;
18514  }
18515  Utilities->CallLogPop(331);
18516  return(true);
18517  }
18518  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18519  {
18520  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18521  NextForwardLinkedRouteNumber = -1;
18522  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18523 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18524  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18525  {
18526  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18527  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18528  {
18529  Attribute = 0;
18530  Utilities->CallLogPop(332);
18531  return(false);
18532  }
18533  //else there is no forward route, so return true with attribute still 0
18534  }
18535  //else there is no forward route, so return true with attribute still 0
18536  }
18537  }
18538  Utilities->CallLogPop(333); //
18539  return(true);
18540 }
18541 
18542 // ---------------------------------------------------------------------------
18543 
18544 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18545 /* Major changes at v2.17.0
18546  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18547 
18548  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18549  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18550  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18551  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18552  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18553  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18554  or (c) truncating a route.
18555 
18556  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18557  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18558  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18559  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18560  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18561  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18562  the function returns true.
18563 
18564  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18565  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18566 */
18567 {
18568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18569  AnsiString(PrefDirVectorStartPosition));
18570  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18571  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18572 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18573 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18574 
18575  if(!PrefDirVector.empty())
18576  {
18577  if(!SkipForwardLook)
18578  {
18579  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18580  {
18581  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18582  if(PrefDirPtr->TrackType == Bridge)
18583  {
18584  if(PrefDirPtr->XLinkPos < 2)
18585  {
18586  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18587  }
18588  else
18589  {
18590  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18591  }
18592  }
18593  if(TrainID != -1)
18594  {
18595  SkipForwardLook = true;
18596  break;
18597  }
18598  }
18599  }
18600 
18602  {
18603  SkipForwardLook = true;
18604  }
18605 
18606  int NextForwardLinkedRouteNumber = -1;
18607  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18608  {
18609  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18611 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18612  if(RouteType == TAllRoutes::NoRoute)
18613  {
18614  SkipForwardLook = true; //if there's no linked forward route then skip
18615  if(PrefDirVector.back().TrackType == Buffers)
18616  {
18617  Attribute = 1; // treat buffer as red signal
18618  }
18619  if(PrefDirVector.back().TrackType == Continuation)
18620  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18621  bool SetAttributeTo3 = true;
18624  {
18625  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18626  AutoSigVectorIT++)
18627  {
18628  if(!AllRoutes->AllRoutesVector.empty())
18629  {
18630  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18631  {
18632  SetAttributeTo3 = false;
18633  Attribute = AutoSigVectorIT->AccessNumber;
18634  break;
18635  }
18636  }
18637  }
18638  }
18639  if(SetAttributeTo3)
18640  {
18641  Attribute = 3; // treat continuation as a green signal
18642  }
18643  }
18644  }
18645  else //startpos still on end element and there is probably a forward route
18646  {
18647  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18648  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18649  {
18650  SkipForwardLook = true; //if there's no linked forward route then skip
18651  if(PrefDirVector.back().TrackType == Buffers)
18652  {
18653  Attribute = 1; // treat buffer as red signal
18654  }
18655  if(PrefDirVector.back().TrackType == Continuation)
18656  {
18657  Attribute = 3; // treat continuation as a green signal
18658  }
18659  }
18660  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18661  }
18662  }
18663 
18664  if(!SkipForwardLook)
18665  {
18666  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18667  //SkipForwardLook will be true - see above)
18668  int StartPos;
18669  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18670  {
18671  StartPos = PrefDirVectorStartPosition + 1;
18672  }
18673  else
18674  {
18675  StartPos = 0; //start of next forward route
18676  }
18677  if(StartPos > 0) //starting in this route
18678  {
18679  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18680  {
18681  StartPos = 0; //reset to 0 for next route
18682  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18683  {
18684  continue;
18685  }
18686  }
18687  }
18688  else //starting in next forward route
18689  {
18690  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18691  {
18692  continue;
18693  }
18694  }
18695  }
18696 
18697  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18698  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18699  {
18700  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18701  if(PrefDirPtr->TrackType == Bridge)
18702  {
18703  if(PrefDirPtr->XLinkPos < 2)
18704  {
18705  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18706  }
18707  else
18708  {
18709  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18710  }
18711  }
18712  if(TrainID != -1)
18713  {
18714  Utilities->CallLogPop(334);
18715  return(false);
18716  }
18717  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18718  // the attribute to 0 so first signal behind the LC is red
18719  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18720  {
18721  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18722  {
18723  Attribute = 0;
18724  }
18725  }
18726 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18727 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18728  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18729  {
18730  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18731  PrefDirPtr->PrefDirRoute)
18732  {
18733 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18734 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18735  int LockedVecNum = 0; //not used
18736  TPrefDirElement DummyPrefDir; //not used
18737  bool KeepAttributeAt0ForLockedRoute = false;
18738  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18739  LockedVecNum))
18740  {
18741  Attribute = 0;
18742  KeepAttributeAt0ForLockedRoute = true;
18743  }
18744 //end of v2.9.2 addition
18745 
18746 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18747  bool NotGroundSignal = false;
18748  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18749  {
18750  NotGroundSignal = true;
18751  }
18752 
18753  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18754  {
18755  Attribute = 0; //stays at 0
18756  }
18757 
18758  if(Attribute < 3)
18759  {
18760  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18761  }
18762  else
18763  {
18764  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18765  }
18766  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18767  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18768  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18769  {
18770  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18771  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18772  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18773  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18774  }
18775  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18776  { //if groundsignal attrib is 0 then do need to increment
18777  Attribute++; //this is for the next signal rearwards, not the current one
18778  }
18779 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18780  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18781  }
18782  }
18783  }
18784  }
18785  Utilities->CallLogPop(335);
18786  return(true);
18787 }
18788 
18789 // ---------------------------------------------------------------------------
18790 
18791 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18792 /*
18793  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18794  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18795  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18796  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18797  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18798  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18799  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18800  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18801 
18802  Note that this function was heavily modified at v2.21.0 when clicking a signal truncates to next signal - with additional conditions, see click table below
18803 */
18804 {
18805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18806  "," + AnsiString((short)PrefDirRoute));
18807  bool ElementInRoute = false;
18808  TOneRoute ReinstatementRoute = *this; //added at v2.21.0 for truncation to next signal
18809  int LastElementToBeTruncated = -1; //added at v2.21.0 for truncation to next signal
18810  bool MovingTrainOccupyingRoute = false;
18811  unsigned int TruncatePDElementPos; //the selected PD position to truncate to & include in the truncation (could be from the back or the front)//added at v2.15.0
18812  enum {NoTruncate, BackTruncate, FrontTruncate, NextSignalTruncate, FullTruncate} TruncateType;
18813  TruncateType = NoTruncate;
18814  AllRoutes->RouteTruncateFlag = false;
18815  //first check the truncate point is in a route
18816  for(unsigned int b = 0; b < PrefDirSize(); b++)
18817  {
18818  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18819  {
18820  TruncatePDElementPos = b;
18821  ElementInRoute = true;
18822  break;
18823  }
18824  }
18825  if(!ElementInRoute)
18826  {
18827  ReturnFlag = NotInRoute;
18828  Utilities->CallLogPop(336);
18829  return;
18830  }
18831 
18832  //click table
18833  //click route sig position result
18834 
18835  //element after signal any mid-route BackTruncate
18836  //element after signal any start of route Not allowed (message given saying would leave single element)
18837  //element before signal any mid-route FrontTruncate
18838  //element before signal any end of route Not allowed (message given saying would leave single element)
18839  //signal any mid-route & signal after that isn't the end NextSignalTruncate
18840  //signal any mid-route & signal after that is the end BackTruncate
18841  //signal any mid-route & no signal after BackTruncate
18842  //signal green or blue end of route Invalid element message
18843  //signal red end of route Erases last element only
18844  //start of route (signal or not)any n/a FullTruncate (never need to clear from entry to next signal as can add a signal)
18845  //end of route (not signal) green or blue n/a Give invalid element message
18846  //end of route (any element) red n/a Erases last element only
18847 
18848  //now find whether back, front, nextsignal (added at v2.21.0) or full truncate //added at v2.15.0, backtrucate = from truncate position to the end of the route (i.e. the original truncate function)
18849  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate as that requires a signal after the truncate point
18850  {
18851  if(TruncatePDElementPos == 0) //start of route
18852  {
18853  TruncateType = FullTruncate;
18854  AllRoutes->RouteTruncateFlag = true; //Added at v2.15.1: Set for all route truncate types, used in SetAllRearwardsSignals to prevent a forward look.
18855  //Without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18856  //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18857  //truncate for that route), the last signal in the autosigs route doesn't change to red.
18858  }
18859  else
18860  {
18861  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18862  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18863  {
18864  TruncateType = FrontTruncate;
18865  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point //added after v2.23.0 because of Fly California/Silicon Airways
18866  } //bug report via discord (ticket #87) where front truncated segment of a green route following a blue route & blue route end signal stayed green
18867  else //here could be back or next signal truncate, next sig truncate if truncate pos is a signal and there's a signal after that isn't the end of the route
18868  {
18869  TempElement = PrefDirVector.at(TruncatePDElementPos);
18870  if(TempElement.Config[TempElement.XLinkPos] == Signal) //possibly next sig truncate
18871  {
18872  TruncatePDElementPos++; //need to add one as in all cases don't want to truncate the signal itself, also there esists a +1 because of the first condition
18873  //now look forwards to next signal, if it's the end or no signal then it's BackTruncate
18874  int b;
18875  for(b = int(TruncatePDElementPos); b < int(PrefDirSize()); b++)
18876  {
18877  TempElement = PrefDirVector.at(b);
18878  if((TempElement.Config[TempElement.XLinkPos] == Signal) && (b < int(PrefDirSize() - 1))) //if met then it's a mid-route signal
18879  {
18880  TruncateType = NextSignalTruncate;
18881  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point - relies on rearwards sig setting before re-instatement route sig setting
18882  break; //re-instatement route sig setting
18883  }
18884  }
18885  if(b == int(PrefDirSize())) //i.e. haven't found a mid-route signal
18886  {
18887  TruncateType = BackTruncate;
18888  AllRoutes->RouteTruncateFlag = true;
18889  }
18890  }
18891  else
18892  {
18893  TruncateType = BackTruncate;
18894  AllRoutes->RouteTruncateFlag = true;
18895  }
18896  }
18897  }
18898  }
18899  else // == PrefDirSize() - 1, i.e. end of route
18900  {
18901  TruncateType = BackTruncate;
18902  AllRoutes->RouteTruncateFlag = true;
18903  }
18904 
18905 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
18906 
18907  if(TruncateType == BackTruncate) //added at v2.15.0
18908  {
18909  for(int b = PrefDirSize() - 1; b >= 0; b--)
18910  {
18911  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18912  if(PrefDirVector.at(b).TrackType == Bridge)
18913  {
18914  if(PrefDirVector.at(b).XLinkPos < 2)
18915  {
18916  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18917  }
18918  else
18919  {
18920  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18921  }
18922  }
18923  if(TrainID != -1)
18924  {
18925  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18926  {
18927  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
18928  }
18929  }
18930  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18931  {
18932  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18933  ReturnFlag = InRouteFalse;
18934  AllRoutes->RouteTruncateFlag = false;
18935  Utilities->CallLogPop(1941);
18936  return;
18937  }
18938  if(b == int(TruncatePDElementPos))
18939  {
18940  break; // OK found truncate element & no flashing LC in front
18941  }
18942  }
18943  }
18944  else if(TruncateType == NextSignalTruncate) //added at v2.15.0
18945  {
18946  //first look forward from truncate point to the next facing signal, which must be mid-route or wouldn't reach here
18947  TPrefDirElement TempElement;
18948  LastElementToBeTruncated = -1;
18949  for(unsigned int b = TruncatePDElementPos; b < PrefDirSize(); b++)
18950  {
18951  TempElement = PrefDirVector.at(b);
18952  if(TempElement.Config[TempElement.XLinkPos] == Signal) //found it
18953  {
18954  LastElementToBeTruncated = int(b) - 1;
18955  break;
18956  }
18957  }
18958  for(int b = LastElementToBeTruncated; b >= 0; b--) //just look for train in section to be erased
18959  {
18960  int TrainID = Track->TrackElementAt(1683, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18961  if(PrefDirVector.at(b).TrackType == Bridge)
18962  {
18963  if(PrefDirVector.at(b).XLinkPos < 2)
18964  {
18965  TrainID = Track->TrackElementAt(1684, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18966  }
18967  else
18968  {
18969  TrainID = Track->TrackElementAt(1685, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18970  }
18971  }
18972  if(TrainID != -1)
18973  {
18974  if(!TrainController->TrainVectorAtIdent(72, TrainID).Stopped())
18975  {
18976  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
18977  }
18978  }
18979  if(Track->IsLCBarrierFlashingAtHV(6, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18980  {
18981  TrainController->StopTTClockMessage(178, "Can't cancel a route containing a level crossing that is changing state");
18982  ReturnFlag = InRouteFalse;
18983  AllRoutes->RouteTruncateFlag = false;
18984  Utilities->CallLogPop(2713);
18985  return;
18986  }
18987  if(b == int(TruncatePDElementPos))
18988  {
18989  break; // OK found truncate element & no flashing LC in front
18990  }
18991  }
18992  //create a new route from the signal forwards to re-instate later
18993  ReinstatementRoute = *this;
18994 // ReinstatementRoute.RouteID = AllRoutes->NextRouteID; //this is allocated when store the route later on
18995 // AllRoutes->NextRouteID++;
18996  ReinstatementRoute.StartRoutePosition = PrefDirVector.at(LastElementToBeTruncated + 1).TrackVectorPosition;
18997  ReinstatementRoute.StartElement1 = PrefDirVector.at(LastElementToBeTruncated + 1);
18998  ReinstatementRoute.StartElement2 = PrefDirVector.at(LastElementToBeTruncated + 1);
18999  ReinstatementRoute.PrefDirVector.erase(ReinstatementRoute.PrefDirVector.begin(), ReinstatementRoute.PrefDirVector.begin() + LastElementToBeTruncated + 1);
19000  ReturnFlag = InRouteTrue;
19001  }
19002  else if(TruncateType == FrontTruncate)//front truncate //added at v2.15.0
19003  {
19004  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
19005  {
19006  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19007  if(PrefDirVector.at(b).TrackType == Bridge)
19008  {
19009  if(PrefDirVector.at(b).XLinkPos < 2)
19010  {
19011  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19012  }
19013  else
19014  {
19015  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19016  }
19017  }
19018  if(TrainID != -1)
19019  {
19020  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
19021  {
19022  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19023  }
19024  }
19025  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19026  {
19027  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
19028  ReturnFlag = InRouteFalse;
19029  AllRoutes->RouteTruncateFlag = false;
19030  Utilities->CallLogPop(2571);
19031  return;
19032  }
19033  if(b == TruncatePDElementPos)
19034  {
19035  break; // OK found truncate element & no flashing LC behind
19036  }
19037  }
19038  }
19039  else //FullTruncate
19040  {
19041  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
19042  {
19043  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19044  if(PrefDirVector.at(b).TrackType == Bridge)
19045  {
19046  if(PrefDirVector.at(b).XLinkPos < 2)
19047  {
19048  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19049  }
19050  else
19051  {
19052  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19053  }
19054  }
19055  if(TrainID != -1)
19056  {
19057  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
19058  {
19059  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19060  }
19061  }
19062  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19063  {
19064  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
19065  ReturnFlag = InRouteFalse;
19066  AllRoutes->RouteTruncateFlag = false;
19067  Utilities->CallLogPop(2572);
19068  return;
19069  }
19070  }
19071  }
19072  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
19073  {
19074  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
19075  ReturnFlag = InRouteFalse;
19076  AllRoutes->RouteTruncateFlag = false;
19077  Utilities->CallLogPop(338);
19078  return;
19079  }
19080  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
19081  {
19082  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
19083  ReturnFlag = InRouteFalse;
19084  AllRoutes->RouteTruncateFlag = false;
19085  Utilities->CallLogPop(339);
19086  return;
19087  }
19088 
19089  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
19090  {
19091  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
19092  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19093  {
19094  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19095  {
19096  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19097  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19098  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19099  "or to remove the whole route select the first track element in the route");
19100  ReturnFlag = InRouteFalse;
19101  AllRoutes->RouteTruncateFlag = false;
19102  Utilities->CallLogPop(340);
19103  return;
19104  }
19105  }
19106  else //this isn't appropriate for front truncate
19107  {
19108  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19109  {
19110  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
19111  ReturnFlag = InRouteFalse;
19112  AllRoutes->RouteTruncateFlag = false;
19113  Utilities->CallLogPop(341);
19114  return;
19115  }
19116  }
19117  }
19118 
19119  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
19120  {
19121  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
19122  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19123  {
19124  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19125  {
19126  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19127  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19128  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19129  "or to remove the whole route select the first track element in the route");
19130  ReturnFlag = InRouteFalse;
19131  AllRoutes->RouteTruncateFlag = false;
19132  Utilities->CallLogPop(2573);
19133  return;
19134  }
19135  }
19136 /*
19137  else //red route //not appropriate for front truncate because the position in advance of the truncation position is to be truncated, it won't be left
19138  { // deleted at v2.21.0
19139  if(TruncatePDElementPos > 0)
19140  {
19141  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
19142  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19143  {
19144  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
19145  ReturnFlag = InRouteFalse;
19146  AllRoutes->RouteTruncateFlag = false;
19147  Utilities->CallLogPop(2574);
19148  return;
19149  }
19150  }
19151  }
19152 */
19153  }
19154 
19155  else if(TruncatePDElementPos == 0) //full truncate
19156  {
19157  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
19158  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
19159  {
19160  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
19161  {
19162  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19163  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19164  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19165  "or to remove the whole route select the first track element in the route");
19166  ReturnFlag = InRouteFalse;
19167  AllRoutes->RouteTruncateFlag = false;
19168  Utilities->CallLogPop(2575);
19169  return;
19170  }
19171  }
19172  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
19173  {
19174  if(TempElement.TrackType == Bridge)
19175  {
19176  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
19177  ReturnFlag = InRouteFalse;
19178  AllRoutes->RouteTruncateFlag = false;
19179  Utilities->CallLogPop(2576);
19180  return;
19181  }
19182  }
19183  }
19184 
19185  int ThisRouteNumber;
19187 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
19188 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
19189 
19190 // check if part of this route already locked & disallow if so
19191  if(!(AllRoutes->LockedRouteVector.empty()))
19192  {
19194  {
19195  if(LRVIT->RouteNumber == ThisRouteNumber)
19196  {
19197  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
19198  ReturnFlag = InRouteFalse;
19199  AllRoutes->RouteTruncateFlag = false;
19200  Utilities->CallLogPop(749);
19201  return;
19202  }
19203  }
19204  }
19205 
19206  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
19207  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //is within 3 running signals on this or linked rearwards routes, NextSigTruncate added at v2.21.0
19208  {
19209  LookBackwardsFromHere = TruncatePDElementPos;
19210  }
19211 
19212 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
19213  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
19214  int FrontPosition;
19215 
19216  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
19217  // before v2.1.0 RouteLockingRequired only checked for trains approaching
19218  {
19219  if(TruncateType == NextSignalTruncate) //added at v2.21.0 - don't allow trucation as would likely need to lock route further forwards than next signal
19220  {
19221  TrainController->StopTTClockMessage(179, "Unable to truncate to next signal when route locking is required. To apply locking truncate from the element "
19222  "immediately after the signal, this will lock the remainder of the route ");
19223  ReturnFlag = InRouteFalse;
19224  AllRoutes->RouteTruncateFlag = false;
19225  Utilities->CallLogPop(2714);
19226  return;
19227  }
19228  else
19229  {
19232  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
19233  L"Warning!", MB_YESNO | MB_ICONWARNING);
19234  TrainController->BaseTime = TDateTime::CurrentDateTime();
19236  if(button == IDNO)
19237  {
19238  ReturnFlag = InRouteTrue; // still return true even though don't act on it
19239  AllRoutes->RouteTruncateFlag = false;
19240  Utilities->CallLogPop(342);
19241  return;
19242  }
19243  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
19244  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
19245  TAllRoutes::TLockedRouteClass LockedRoute;
19246  bool ExistingLockedRouteModified = false;
19247  LockedRoute.RouteNumber = ThisRouteNumber;
19248  if(TruncateType == BackTruncate)
19249  {
19250  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19251  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19252  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19253  }
19254  else if(TruncateType == FrontTruncate)
19255  {
19256  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19257  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19258  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
19259  }
19260  else //FullTruncate
19261  {
19262  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19263  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19264  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19265  }
19266 
19267  LockedRoute.LockStartTime = TrainController->TTClockTime;
19268  // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
19269  // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
19270  if(!AllRoutes->LockedRouteVector.empty())
19271  {
19272  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
19273  LRVIT++)
19274  {
19275  if(LRVIT->RouteNumber == ThisRouteNumber)
19276  {
19277  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
19278  LRVIT->LockStartTime = LockedRoute.LockStartTime;
19279  ExistingLockedRouteModified = true;
19280  }
19281  }
19282  }
19283  if(!ExistingLockedRouteModified)
19284  {
19285  AllRoutes->LockedRouteVector.push_back(LockedRoute);
19286  }
19287  if(TruncateType == BackTruncate)
19288  {
19289  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
19290  RearPosition = TruncatePDElementPos;
19291  FrontPosition = PrefDirSize() - 1;
19292  }
19293  else if(TruncateType == FrontTruncate)
19294  {
19295  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
19296  RearPosition = 0;
19297  FrontPosition = TruncatePDElementPos;
19298  }
19299  else //FullTruncate
19300  {
19301  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
19302  RearPosition = 0;
19303  FrontPosition = PrefDirSize() - 1;
19304  }
19305  // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
19306  for(int c = FrontPosition; c >= RearPosition; c--)
19307  {
19308  // return all signals to red in route section to be truncated
19309  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
19310  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
19311  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
19312  {
19313  TrackElement.Attribute = 0;
19314  Track->PlotSignal(2, TrackElement, Display);
19315  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
19316  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
19317  }
19318  }
19319  // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
19320  ReturnFlag = InRouteTrue;
19321  }
19322  }
19323  else //route locking not required
19324  {
19325  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //need to erase the whole route to the end, the new bit will be re-instated later
19326  { //for NextSignalTruncate
19327  RearPosition = TruncatePDElementPos;
19328  FrontPosition = PrefDirSize() - 1;
19329  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
19330  }
19331  else if(TruncateType == FrontTruncate)
19332  {
19333  RearPosition = 0;
19334  FrontPosition = TruncatePDElementPos;
19335  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
19336  }
19337  else //FullTruncate
19338  {
19339  RearPosition = 0;
19340  FrontPosition = PrefDirSize() - 1;
19341  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
19342  }
19343 
19344  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
19345  //into adjacent red or green routes if there are any (after the truncation/removal)
19346 
19347  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19348  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
19349 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
19350 
19351  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
19352  {
19353  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
19354  ReturnFlag = InRouteTrue;
19355  }
19356 
19357  if(TruncateType == NextSignalTruncate) //re-instate the saved route
19358  {
19359  AllRoutes->RouteTruncateFlag = false; //added at v2.22.0, not truncating any longer so don't want to set SkipForwardLook when setting rearward signals
19360  AllRoutes->StoreOneRoute(3, &ReinstatementRoute);
19362  int RouteNumber = AllRoutes->GetRouteVectorNumber(8, IDInt(RouteID));
19363  AllRoutes->SetAllRearwardsSignals(22, 0, RouteNumber, ReinstatementRoute.PrefDirSize() - 1); //sets signals for the re-instated route
19364  }
19365  if(LastPDElement.AutoSignals)
19366  {
19367  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
19368  }
19369  }
19370 
19371  AllRoutes->CheckMapAndRoutes(5); // test
19372  ReturnFlag = InRouteTrue;
19373  AllRoutes->RouteTruncateFlag = false;
19374  Utilities->CallLogPop(344);
19375 }
19376 
19377 // ---------------------------------------------------------------------------
19378 
19380 {
19381 /*
19382 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
19383 signal.
19384 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
19385  but a new route that is created TO a signal - that signal becomes part of the new route.
19386 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
19387 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
19388  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
19389  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
19390  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
19391  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
19392  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
19393 */
19394 
19395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
19396  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
19397  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
19398  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
19399  {
19400  Utilities->CallLogPop(2578);
19401  return;
19402  }
19403  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
19404  int RouteColour;
19405  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
19406  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19407  {
19408  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
19409  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
19410  { //found a linked forward route
19411  //check if signal behind this route has been removed from the blue route
19412  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19413  { //signal needs to be added at start of this linked route
19414 
19415  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
19416  if(RouteColour == 1) //red route
19417  {
19418  NewRedFirstPDElement = LastPDElement;
19419  NewRedFirstPDElement.AutoSignals = false;
19420  NewRedFirstPDElement.PrefDirRoute = false;
19421  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19422  NewRedFirstPDElement.IsARoute = true;
19423  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
19424  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
19425  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19426  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19427  {
19428  if(R2MMIt->second.first == int(x))
19429  {
19430  R2MMIt->second.second++;
19431  }
19432  }
19433  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19434  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19435  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19436  }
19437  else if(RouteColour == 2) //green route
19438  {
19439  NewGreenFirstPDElement = LastPDElement;
19440  NewGreenFirstPDElement.AutoSignals = false;
19441  NewGreenFirstPDElement.PrefDirRoute = true;
19442  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19443  NewGreenFirstPDElement.IsARoute = true;
19444  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19445  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19446  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19447  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19448  {
19449  if(R2MMIt->second.first == int(x))
19450  {
19451  R2MMIt->second.second++;
19452  }
19453  }
19454  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19455  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19456  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19457  }
19458  }
19459  break; //no point looking any further
19460  }
19461  }
19462 
19463 //check if there's a linked rearward route missing a signal and if so add it
19464  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19465  {
19466  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19467  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19468  { //found a linked rearward route
19469  //check if signal in front of this route has been removed from the blue route
19470  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19471  { //signal needs to be added at end of this linked route
19472 
19473  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19474  if(RouteColour == 1) //red route
19475  {
19476  NewRedLastPDElement = FirstPDElement;
19477  NewRedLastPDElement.AutoSignals = false;
19478  NewRedLastPDElement.PrefDirRoute = false;
19479  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19480  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19481  //can use this as adding to the end of the route
19482  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19483  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19484  }
19485  else if(RouteColour == 2) //green route
19486  {
19487  NewGreenLastPDElement = FirstPDElement;
19488  NewGreenLastPDElement.AutoSignals = false;
19489  NewGreenLastPDElement.PrefDirRoute = true;
19490  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19491  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19492  //can use this as adding to the end of the route
19493  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19494  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19495  }
19496  }
19497  break; //no point looking any further
19498  }
19499  }
19500  Utilities->CallLogPop(2579);
19501 }
19502 
19503 // ---------------------------------------------------------------------------
19504 
19506 /*
19507  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19508  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19509  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19510  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19511  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19512  the route colours.
19513 */
19514 {
19515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19516  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19518  int RouteNumber;
19519  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19520  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19521  //these added at v2.15.0
19522  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19523  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19524 
19525  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19526  {
19527  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19528  {
19529  if(PrefDirVector.at(x).TrackType == SignalPost)
19530  {
19531  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19532  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19533  }
19534  }
19535 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19536  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19537  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19538  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19539  //when should have been be red.
19540 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19541  }
19542  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19543  {
19544  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19545  }
19546 
19547  if(LastPDElement.AutoSignals) //added at v2.15.0
19548  {
19549  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19550  }
19551 
19552  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19553  {
19554  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19555  {
19556  ARVIt->SetRouteSignals(14);
19557  }
19558  }
19559  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19560  AllRoutes->CheckMapAndRoutes(9); // test
19561  TrainController->BaseTime = TDateTime::CurrentDateTime();
19563  Utilities->CallLogPop(345);
19564  return;
19565 }
19566 
19567 // ---------------------------------------------------------------------------
19568 
19569 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19570 /*
19571  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19572 */
19573 {
19574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19575  AnsiString((short)PrefDirRoute));
19576  if(SearchVector.empty())
19577  {
19578  Utilities->CallLogPop(1149);
19579  return;
19580  }
19581  for(unsigned int b = 0; b < SearchVector.size(); b++)
19582  {
19585  PrefDirRoute);
19586  }
19587  Utilities->CallLogPop(346);
19588 }
19589 
19590 // ---------------------------------------------------------------------------
19591 
19592 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19593 /*
19594  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19595  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19596  TOneRoute.
19597 */
19598 {
19599  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19600  AnsiString((short)PrefDirRoute));
19601  RouteFlash.RouteFlashVector.clear();
19602  TRouteFlashElement RouteFlashElement;
19603 
19604  for(unsigned int b = 0; b < SearchVector.size(); b++)
19605  {
19606  int H = GetFixedSearchElementAt(11, b).HLoc;
19607  int V = GetFixedSearchElementAt(12, b).VLoc;
19609  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19610  RouteFlashElement.HLoc = H;
19611  RouteFlashElement.VLoc = V;
19613  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19614  }
19615  Utilities->CallLogPop(348);
19616 }
19617 
19618 // ---------------------------------------------------------------------------
19619 
19620 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19621 {
19622  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19623  if(!PrefDirVector.empty())
19624  {
19625  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19626  {
19627  int H = PrefDirPtr->HLoc;
19628  int V = PrefDirPtr->VLoc;
19629  // check for any LCs that are closed to trains & set the flash values and store in the vector
19630  if(Track->IsLCAtHV(39, H, V))
19631  {
19632  if(Track->IsLCBarrierUpAtHV(0, H, V))
19633  {
19634  Track->LCChangeFlag = true;
19635  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19636  CLC.HLoc = H;
19637  CLC.VLoc = V;
19639  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19642  if(PrefDirRoute)
19643  {
19644  CLC.TypeOfRoute = 1;
19645  }
19646  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19647  Track->ChangingLCVector.push_back(CLC);
19648  }
19649  }
19650  }
19651  }
19652  Utilities->CallLogPop(1948);
19653 }
19654 
19655 // ---------------------------------------------------------------------------
19656 
19658 /*
19659  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19660  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19661  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19662  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19663 */
19664 {
19665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19666  if(!OverlayPlotted)
19667  {
19668  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19669  {
19670  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19671  {
19672  continue;
19673  }
19674  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19675  Display->Update();
19676  }
19677  OverlayPlotted = true;
19678  }
19679  Utilities->CallLogPop(349);
19680 }
19681 
19682 // ---------------------------------------------------------------------------
19683 
19685 /*
19686  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19687  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19688  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19689  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19690 */
19691 {
19692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19693  if(OverlayPlotted)
19694  {
19695  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19696  {
19697  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19698  {
19699  continue;
19700  }
19701  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19702  Display->Update();
19703  }
19704  OverlayPlotted = false;
19705  }
19706  Utilities->CallLogPop(350);
19707 }
19708 
19709 // ---------------------------------------------------------------------------
19710 
19711 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19712 {
19713 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19714 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19715 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19716 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19717 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19718 messages, and allocate a repair time similar to points)
19719 */
19720 
19721  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19722  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19723  {
19724  Utilities->CallLogPop(2528);
19725  return(false);
19726  }
19727  bool FirstSignalFound = false;
19728  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19729  {
19730  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19731 //check for a failed point where needs to change to make the route
19732 //shouldn't be any but check to be safe
19733  int Attr = TE.Attribute;
19734  if(PDVIt->TrackType == Points)
19735  {
19736  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19737  {
19738  if(Attr == 1) //currently set to diverge
19739  {
19740  if(TE.Failed)
19741  {
19742  Utilities->CallLogPop(2529);
19743  return(false); //return without further checking
19744  }
19745  }
19746  }
19747  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19748  {
19749  if(Attr == 0) //currently set to go straight
19750  {
19751  if(TE.Failed)
19752  {
19753  Utilities->CallLogPop(2530);
19754  return(false); //return without further checking
19755  }
19756  }
19757  }
19758  }
19759  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19760  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19761  //the search vector)
19762  int XLinkPosition = PDVIt->XLinkPos;
19763  if(PDVIt->XLinkPos == -1)
19764  {
19765  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19766  {
19767  for(int x = 0; x < 4; x++)
19768  {
19769  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19770  {
19771  XLinkPosition = x;
19772  break;
19773  }
19774  }
19775  }
19776  else
19777  {
19778  Utilities->CallLogPop(2549);
19779  return(false); //no point going any further
19780  }
19781  }
19782  if(XLinkPosition > -1) //should be by now but be safe
19783  {
19784  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19785  {
19786  FirstSignalFound = true; //the first signal doesn't change aspect
19787  continue;
19788  }
19789  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19790  {
19791 /*
19792  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19793  {
19794  continue; //ground signals don't fail
19795  }
19796 */
19797  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19798  {
19800  IFE.TVPos = PDVIt->TrackVectorPosition;
19801  TE.Failed = true;
19802  TE.Attribute = 0; //stop aspect
19803  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19804  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19805  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19806  " failed when changing aspect.\nTrains can only pass under signaller control.");
19807  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19808  //set repair time, random value in minutes between 10 and 179
19809  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19810  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19811  IFE.RepairTime = RepairTime;
19813  Track->FailedSignalsVector.push_back(IFE);
19815  int RouteNumber; //not used
19816  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19817  { // 0 for LinkPos ok as a signal so only one track
19818  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19819  }
19820  Utilities->CallLogPop(2535);
19821  return(true); //return so only allow one failure per route
19822  }
19823  }
19824  }
19825  }
19826  Utilities->CallLogPop(2531);
19827  return(false);
19828 }
19829 
19830 // ---------------------------------------------------------------------------
19831 // ---------------------------------------------------------------------------
19832 
19833 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19834 {
19835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19836  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19837  {
19838  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19839  }
19840  Utilities->CallLogPop(120);
19841  return(AllRoutesVector.at(At));
19842 }
19843 
19844 // ---------------------------------------------------------------------------
19845 
19847 {
19848  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19849  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19850  {
19851  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19852  }
19853  Utilities->CallLogPop(121);
19854  return(AllRoutesVector.at(At));
19855 }
19856 
19857 // ---------------------------------------------------------------------------
19858 
19859 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19860 /*
19861  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19862 */
19863 {
19864  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19865  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19866  {
19867  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19868  }
19869  Utilities->CallLogPop(351);
19870 }
19871 
19872 // ---------------------------------------------------------------------------
19873 
19874 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19875 {
19876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
19877  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19878  {
19879  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
19880  }
19881  Utilities->CallLogPop(1706);
19882 }
19883 
19884 // ---------------------------------------------------------------------------
19885 
19886 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
19887 /*
19888  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
19889  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
19890  Messages are given in TruncateRoute. If successful the route is truncated at and including
19891  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
19892  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
19893  length (train length).
19894 */
19895 {
19896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
19897  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
19898  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19899  {
19900  TTruncateReturnType ReturnFlag;
19901 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
19902  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
19903  if(ReturnFlag == NotInRoute)
19904  {
19905  continue;
19906  }
19907  else if(ReturnFlag == InRouteTrue)
19908  {
19909  Utilities->CallLogPop(352);
19910  return(true);
19911  }
19912  else if(ReturnFlag == InRouteFalse)
19913  {
19914  Utilities->CallLogPop(353);
19915  return(false);
19916  }
19917  }
19918  Utilities->CallLogPop(354);
19919  return(false);
19920 }
19921 
19922 // ---------------------------------------------------------------------------
19923 
19924 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
19925 /*
19926  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
19927  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
19928 */
19929 {
19930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
19931  AnsiString(LinkPos));
19932  if(TrackVectorPosition == -1) // allows for continuation entries & exits
19933  {
19934  Utilities->CallLogPop(355);
19935  return(false);
19936  }
19937  THVPair Route2MultiMapKeyPair;
19938 
19939  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
19940  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
19941  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19942  TRoute2MultiMapIterator Route2MultiMapIterator;
19943 
19944  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
19945  {
19946  Utilities->CallLogPop(356);
19947  return(false);
19948  }
19949  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
19950  {
19951  Utilities->CallLogPop(1422);
19952  return(true);
19953  }
19954  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
19955  {
19956  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19957 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19958 // realised after writing this that can't be points as would have been covered above, but leave anyway
19959  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
19960  Route2MultiMapIterator->second.second);
19961  EntryLinkPos = PrefDirElement1.ELinkPos;
19962  ExitLinkPos = PrefDirElement1.XLinkPos;
19963  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19964  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19965  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
19966  {
19967  Utilities->CallLogPop(357);
19968  return(true);
19969  }
19970  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
19971  {
19972  Utilities->CallLogPop(358);
19973  return(true);
19974  }
19975  }
19976  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
19977  {
19978  Utilities->CallLogPop(1423);
19979  return(true);
19980  }
19981  Utilities->CallLogPop(363);
19982  return(false); // none found
19983 }
19984 
19985 // ---------------------------------------------------------------------------
19986 
19987 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
19988  Graphics::TBitmap* &EntryDirectionGraphicPtr)
19989 /*
19990  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
19991  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
19992  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
19993  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
19994  for replotting of AutoSigsRoutes.
19995 */
19996 {
19997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19998  AnsiString(LinkPos));
19999  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
20000  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
20001  if(TrackVectorPosition == -1)
20002  {
20003  Utilities->CallLogPop(364);
20004  return(NoRoute); // allows for continuation entries & exits
20005  }
20006  THVPair Route2MultiMapKeyPair;
20007 
20008  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
20009  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
20010  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20011  TRoute2MultiMapIterator Route2MultiMapIterator;
20012 
20013  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20014  {
20015  Utilities->CallLogPop(365);
20016  return(NoRoute); // none found
20017  }
20018  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20019  {
20020  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20021 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20022  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
20023  Route2MultiMapIterator->second.second);
20024  EntryLinkPos = PrefDirElement1.ELinkPos;
20025  ExitLinkPos = PrefDirElement1.XLinkPos;
20026  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20027  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20028  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
20029  {
20030  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20031  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
20032  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20033  {
20034  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20035  }
20036  if(PrefDirElement1.AutoSignals)
20037  {
20038  Utilities->CallLogPop(366);
20039  return(AutoSigsRoute);
20040  }
20041  else
20042  {
20043  Utilities->CallLogPop(367);
20044  return(NotAutoSigsRoute);
20045  }
20046  }
20047  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
20048  {
20049  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20050  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
20051  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20052  {
20053  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20054  }
20055  if(PrefDirElement1.AutoSignals)
20056  {
20057  Utilities->CallLogPop(368);
20058  return(AutoSigsRoute);
20059  }
20060  else
20061  {
20062  Utilities->CallLogPop(369);
20063  return(NotAutoSigsRoute);
20064  }
20065  }
20066  }
20067  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20068  {
20069  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20070  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20071 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20072  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
20073  EntryLinkPos = PrefDirElement2.ELinkPos;
20074  ExitLinkPos = PrefDirElement2.XLinkPos;
20075  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20076  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20077  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
20078  {
20079  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20080  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
20081  {
20082  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20083  }
20084  if(PrefDirElement2.AutoSignals)
20085  {
20086  Utilities->CallLogPop(370);
20087  return(AutoSigsRoute);
20088  }
20089  else
20090  {
20091  Utilities->CallLogPop(371);
20092  return(NotAutoSigsRoute);
20093  }
20094  }
20095  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
20096  {
20097  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20098  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
20099  {
20100  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20101  }
20102  if(PrefDirElement2.AutoSignals)
20103  {
20104  Utilities->CallLogPop(372);
20105  return(AutoSigsRoute);
20106  }
20107  else
20108  {
20109  Utilities->CallLogPop(373);
20110  return(NotAutoSigsRoute);
20111  }
20112  }
20113  ItPair.second--; // the second iterator points one past the last matching value
20114  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
20115  EntryLinkPos = PrefDirElement3.ELinkPos;
20116  ExitLinkPos = PrefDirElement3.XLinkPos;
20117  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20118  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20119  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
20120  {
20121  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20122  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
20123  {
20124  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20125  }
20126  if(PrefDirElement3.AutoSignals)
20127  {
20128  Utilities->CallLogPop(374);
20129  return(AutoSigsRoute);
20130  }
20131  else
20132  {
20133  Utilities->CallLogPop(375);
20134  return(NotAutoSigsRoute);
20135  }
20136  }
20137  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
20138  {
20139  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20140  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
20141  {
20142  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20143  }
20144  if(PrefDirElement3.AutoSignals)
20145  {
20146  Utilities->CallLogPop(376);
20147  return(AutoSigsRoute);
20148  }
20149  else
20150  {
20151  Utilities->CallLogPop(377);
20152  return(NotAutoSigsRoute);
20153  }
20154  }
20155  }
20156  Utilities->CallLogPop(378);
20157  return(NoRoute); // none found
20158 }
20159 
20160 // ---------------------------------------------------------------------------
20161 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
20162 /*
20163  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
20164  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
20165 */
20166 {
20167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
20168  AnsiString(LinkPos));
20169  if(TrackVectorPosition == -1)
20170  {
20171  RouteNumber = -1;
20172  Utilities->CallLogPop(379);
20173  return(NoRoute); // allows for continuation & buffer entries & exits
20174  }
20175  THVPair Route2MultiMapKeyPair;
20176 
20177  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
20178  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
20179  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20180  TRoute2MultiMapIterator Route2MultiMapIterator;
20181 
20182  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20183  {
20184  RouteNumber = -1;
20185  Utilities->CallLogPop(380);
20186  return(NoRoute); // none found
20187  }
20188  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20189  {
20190  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20191 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20192  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
20193  Route2MultiMapIterator->second.second);
20194  EntryLinkPos = PrefDirElement1.ELinkPos;
20195  ExitLinkPos = PrefDirElement1.XLinkPos;
20196  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20197  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20198  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
20199  {
20200  RouteNumber = Route2MultiMapIterator->second.first;
20201  if(PrefDirElement1.AutoSignals)
20202  {
20203  Utilities->CallLogPop(381);
20204  return(AutoSigsRoute);
20205  }
20206  else
20207  {
20208  Utilities->CallLogPop(382);
20209  return(NotAutoSigsRoute);
20210  }
20211  }
20212  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
20213  {
20214  RouteNumber = Route2MultiMapIterator->second.first;
20215  if(PrefDirElement1.AutoSignals)
20216  {
20217  Utilities->CallLogPop(383);
20218  return(AutoSigsRoute);
20219  }
20220  else
20221  {
20222  Utilities->CallLogPop(384);
20223  return(NotAutoSigsRoute);
20224  }
20225  }
20226  }
20227  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20228  {
20229  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20230  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20231 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20232  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
20233  EntryLinkPos = PrefDirElement2.ELinkPos;
20234  ExitLinkPos = PrefDirElement2.XLinkPos;
20235  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20236  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20237  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
20238  {
20239  RouteNumber = ItPair.first->second.first;
20240  if(PrefDirElement2.AutoSignals)
20241  {
20242  Utilities->CallLogPop(385);
20243  return(AutoSigsRoute);
20244  }
20245  else
20246  {
20247  Utilities->CallLogPop(386);
20248  return(NotAutoSigsRoute);
20249  }
20250  }
20251  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
20252  {
20253  RouteNumber = ItPair.first->second.first;
20254  if(PrefDirElement2.AutoSignals)
20255  {
20256  Utilities->CallLogPop(387);
20257  return(AutoSigsRoute);
20258  }
20259  else
20260  {
20261  Utilities->CallLogPop(388);
20262  return(NotAutoSigsRoute);
20263  }
20264  }
20265  ItPair.second--; // the second iterator points one past the last matching value
20266  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
20267  EntryLinkPos = PrefDirElement3.ELinkPos;
20268  ExitLinkPos = PrefDirElement3.XLinkPos;
20269  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20270  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20271  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
20272  {
20273  RouteNumber = ItPair.second->second.first;
20274  if(PrefDirElement3.AutoSignals)
20275  {
20276  Utilities->CallLogPop(389);
20277  return(AutoSigsRoute);
20278  }
20279  else
20280  {
20281  Utilities->CallLogPop(390);
20282  return(NotAutoSigsRoute);
20283  }
20284  }
20285  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
20286  {
20287  RouteNumber = ItPair.second->second.first;
20288  if(PrefDirElement3.AutoSignals)
20289  {
20290  Utilities->CallLogPop(391);
20291  return(AutoSigsRoute);
20292  }
20293  else
20294  {
20295  Utilities->CallLogPop(392);
20296  return(NotAutoSigsRoute);
20297  }
20298  }
20299  }
20300  RouteNumber = -1;
20301  Utilities->CallLogPop(393);
20302  return(NoRoute); // none found
20303 }
20304 
20305 // ---------------------------------------------------------------------------
20306 
20307 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
20308 /*
20309  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
20310  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
20311  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
20312  and Route2MultiMap.
20313 */
20314 {
20315  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
20316  TOneRoute EmptyRoute;
20317 
20318  EmptyRoute.RouteID = NextRouteID;
20319  NextRouteID++;
20320 
20321  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20322  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20323  {
20324  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
20325  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
20326  }
20327  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
20328  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
20329  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
20330  Utilities->CallLogPop(394);
20331 }
20332 
20333 // ---------------------------------------------------------------------------
20334 
20336 /*
20337  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
20338  that is already in Route is used.
20339 */
20340 {
20341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
20342  TOneRoute EmptyRoute;
20343 
20344  EmptyRoute.RouteID = Route->RouteID;
20345 
20346  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20347  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20348  {
20349  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
20350  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
20351  }
20352  Utilities->CallLogPop(1579);
20353 }
20354 
20355 // ---------------------------------------------------------------------------
20356 
20357 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
20358 /*
20359  When attaching a new route section to an existing route, it is sometimes necessary to erase the
20360  original route and create a new composite route. This function Erases all elements in the route
20361  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
20362  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
20363  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
20364  that are greater than the route number that is removed. The LockedRouteVector as also searched
20365  and if any relate to the route that has been cleared they are erased too, but the fact that one
20366  has been found is recorded so that it can be re-established later.
20367 */
20368 {
20369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
20370  THVPair Route2MultiMapKeyPair;
20371  TRoute2MultiMapEntry Route2MultiMapEntry;
20372  TRoute2MultiMapIterator Route2MultiMapIterator;
20373 
20374 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
20375 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
20376 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
20377 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
20378 // If so the locked route is removed from the locked vector and is lost.
20379  LockedRouteRearTrackVectorPosition = 0;
20380  LockedRouteLastTrackVectorPosition = 0;
20381  LockedRouteLastXLinkPos = 0;
20382  LockedRouteLockStartTime = TDateTime(0);
20383  if(!LockedRouteVector.empty())
20384  {
20385  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20386  {
20387  if(LRVIT->RouteNumber == RouteNumber)
20388  {
20389  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
20390  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
20391  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
20392  LockedRouteLockStartTime = LRVIT->LockStartTime;
20393  LockedRouteFoundDuringRouteBuilding = true;
20394  LockedRouteVector.erase(LRVIT);
20395  }
20396  }
20397  }
20398  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
20399  {
20400  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
20401  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
20402  }
20403  Utilities->CallLogPop(395);
20404 }
20405 
20406 // ---------------------------------------------------------------------------
20407 
20409  TRoute2MultiMapIterator &Route2MultiMapIterator)
20410 /*
20411  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
20412  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
20413  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
20414  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
20415  are given for failure.
20416 */
20417 {
20418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20419  AnsiString(VLoc) + "," + AnsiString(ELink));
20420  TRouteElementPair ReturnPair;
20421 
20422  ReturnPair.first = -1;
20423  ReturnPair.second = 0;
20424  THVPair Route2MultiMapKeyPair;
20425 
20426  Route2MultiMapKeyPair.first = HLoc;
20427  Route2MultiMapKeyPair.second = VLoc;
20428  TRoute2MultiMapEntry Route2MultiMapEntry;
20429 
20430  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20431  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20432 
20433  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20434  Route2MultiMapIterator = ItPair.first;
20435 
20436  if(ItPair.first == ItPair.second)
20437  {
20438  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20439  }
20440  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20441  {
20442  ReturnPair.first = ItPair.first->second.first;
20443  ReturnPair.second = ItPair.first->second.second;
20444  Route2MultiMapIterator = ItPair.first;
20445  Utilities->CallLogPop(396);
20446  return(ReturnPair);
20447  }
20448  ItPair.first++;
20449  if(ItPair.first == ItPair.second)
20450  {
20451  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20452  }
20453  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20454  {
20455  ReturnPair.first = ItPair.first->second.first;
20456  ReturnPair.second = ItPair.first->second.second;
20457  Route2MultiMapIterator = ItPair.first;
20458  Utilities->CallLogPop(397);
20459  return(ReturnPair);
20460  }
20461  Utilities->CallLogPop(398);
20462  return(ReturnPair);
20463 }
20464 
20465 // ---------------------------------------------------------------------------
20466 
20467 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20468 /*
20469  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20470  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20471  RouteNumber (route position in AllRoutes vector is returned as a reference.
20472  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20473  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20474 */
20475 {
20476  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20477  AnsiString(VLoc) + "," + AnsiString(ELink));
20478  THVPair Route2MultiMapKeyPair;
20479 
20480  Route2MultiMapKeyPair.first = HLoc;
20481  Route2MultiMapKeyPair.second = VLoc;
20482  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20483 
20484  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20485 
20486  if(ItPair.first == ItPair.second)
20487  {
20488  RouteNumber = -1;
20489  Utilities->CallLogPop(2032);
20490  return(false);
20491  }
20492  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20493  {
20494  RouteNumber = ItPair.first->second.first;
20495  Utilities->CallLogPop(2033);
20496  return(true);
20497  }
20498  ItPair.first++;
20499 
20500  if(ItPair.first == ItPair.second)
20501  {
20502  RouteNumber = -1;
20503  Utilities->CallLogPop(2034);
20504  return(false);
20505  }
20506  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20507  {
20508  RouteNumber = ItPair.first->second.first;
20509  Utilities->CallLogPop(2035);
20510  return(true);
20511  }
20512  RouteNumber = -1;
20513  Utilities->CallLogPop(2036);
20514  return(false);
20515 }
20516 
20517 // ---------------------------------------------------------------------------
20518 
20519 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20520 /*
20521  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20522  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20523  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20524  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20525  Called by TAllRoutes::AddRouteElement.
20526 */
20527 {
20528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20529  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20530  THVPair Route2MultiMapKeyPair;
20531 
20532  Route2MultiMapKeyPair.first = HLoc;
20533  Route2MultiMapKeyPair.second = VLoc;
20534  TRoute2MultiMapEntry Route2MultiMapEntry;
20535 
20536  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20537  TRouteElementPair RouteElementPair;
20538 
20539  RouteElementPair.first = RouteNumber;
20540  RouteElementPair.second = RouteElementNumber;
20541  Route2MultiMapEntry.second = RouteElementPair;
20542 
20543  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20544  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20545  {
20546  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20547  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20548  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20549  {
20550  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20551  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20552  {
20553  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20554  }
20555  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20556  }
20557  else
20558  // same ELink so have an error
20559  {
20560  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20561  }
20562  }
20563  else
20564  {
20565  Route2MultiMap.insert(Route2MultiMapEntry);
20566  }
20567 // element at H&V not found in map so insert it
20568  Utilities->CallLogPop(399);
20569 }
20570 
20571 // ---------------------------------------------------------------------------
20572 
20574 /*
20575  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20576  and the second in the reference SecondPair. If there's only one then it's the function return
20577 */
20578 {
20579  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20580  AnsiString(VLoc));
20582 
20583  TempPair.first = -1;
20584  TempPair.second = 0;
20585  SecondPair = TempPair;
20586  TRoute2MultiMapIterator Route2MultiMapIterator;
20587  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20588  THVPair Route2MultiMapKeyPair;
20589 
20590  Route2MultiMapKeyPair.first = HLoc;
20591  Route2MultiMapKeyPair.second = VLoc;
20592  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20593  {
20594  Utilities->CallLogPop(400);
20595  return(TempPair);
20596  }
20597  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20598  {
20599  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20600  Utilities->CallLogPop(401);
20601  return(Route2MultiMapIterator->second);
20602  }
20603  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20604  {
20605  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20606  TempPair = ItRange.first->second;
20607  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20608  Utilities->CallLogPop(402);
20609  return(TempPair);
20610  }
20611  Utilities->CallLogPop(403);
20612  return(TempPair);
20613 }
20614 
20615 // ---------------------------------------------------------------------------
20616 
20617 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20618 /*
20619  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20620  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20621 */
20622 {
20623  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20624  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20625  {
20626  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20627  {
20628  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20629  TAllRoutes::TRouteElementPair SecondPair;
20630  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20631  if(RouteElementPair.first == -1)
20632  // failed to find element in multimap
20633  {
20634  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20635  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20636  }
20637  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20638  // neither pair has expected route number
20639  {
20640  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20641  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20642  (AnsiString)Caller);
20643  }
20644  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20645  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20646  {
20647  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20648  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20649  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20650  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20651  }
20652  }
20653  }
20654  unsigned int SizeVal = 0;
20655 
20656 // check map and sum of route sizes match
20657  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20658  {
20659  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20660  }
20661  if(SizeVal != Route2MultiMap.size())
20662  {
20663  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20664  (AnsiString)Caller);
20665  }
20666  Utilities->CallLogPop(404);
20667  return;
20668 }
20669 
20670 // ---------------------------------------------------------------------------
20671 
20672 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20673 /*
20674  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20675  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20676  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20677 */
20678 {
20679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20680  if(!Route2MultiMap.empty())
20681  {
20682  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20683  {
20684  if(Route2MultiMapIterator->second.first > RouteNumber)
20685  {
20686  Route2MultiMapIterator->second.first--;
20687  }
20688  }
20689  }
20690  Utilities->CallLogPop(405);
20691 }
20692 
20693 // ---------------------------------------------------------------------------
20694 
20695 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20696 /*
20697  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20698  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20699  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20700 */
20701 {
20702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20703  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20704  if(!Route2MultiMap.empty())
20705  {
20706  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20707  {
20708  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20709  {
20710  Route2MultiMapIterator->second.second--;
20711  }
20712  }
20713  }
20714  Utilities->CallLogPop(406);
20715 }
20716 
20717 // ---------------------------------------------------------------------------
20718 
20719 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20720 /*
20721  Erases the route element from Route2MultiMap and from the PrefDirVector.
20722  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20723  decremented if they are greater than the element number removed, and if the entire route is removed
20724  then the route numbers are also decremented in the map for route numbers that are greater than the route
20725  number that is removed.
20726 */
20727 {
20728  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20729  AnsiString(ELink));
20730  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20731  TRoute2MultiMapIterator Route2MultiMapIterator;
20732 
20733  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20734  if(RequiredRoutePair.first == -1)
20735  {
20736  throw Exception("Failed to find route element in RemoveRouteElement");
20737  }
20738  Route2MultiMap.erase(Route2MultiMapIterator);
20739  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20740 
20741 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20742  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20743 
20744  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20745  {
20746  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20747  }
20748 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20749 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20750 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20751 // to check if a route element is present, and the element has already been removed from the map - see above.
20752 
20753 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20754 /*
20755  int LockedVectorNumber = -1;
20756  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20757  {
20758  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20759  }
20760 */
20761 
20762 // erase element from route
20763  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20764 // CheckMapAndRoutes();//test - drop - tested below
20765 
20766 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20767 // be so as continuation exit is at the end of the route, and truncation is from the end
20769  {
20771  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20772  AutoSigVectorIT--)
20773  {
20774  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20775  {
20776  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20777  }
20778  }
20779  }
20780 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20781 // and adjust all the corresponding route numbers
20782  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20783  {
20784  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20785  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20786  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20787 
20788 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20789  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20790  it is erased then - see TInterface::ApproachLocking
20791 
20792  if(LockedVectorNumber > -1)
20793  {
20794  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20795  }
20796 */
20797  // decrement route numbers in the locked route vector whether or not this route is a locked route
20798  if(!LockedRouteVector.empty())
20799  {
20800  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20801  {
20802  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20803  {
20804  LRVIT->RouteNumber--;
20805  }
20806  }
20807  }
20809  {
20811  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20812  AutoSigVectorIT--)
20813  {
20814  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20815  {
20816  AutoSigVectorIT->RouteNumber--;
20817  }
20818  }
20819  }
20820  }
20821  CheckMapAndRoutes(7); // test
20822  Utilities->CallLogPop(407);
20823 }
20824 
20825 // ---------------------------------------------------------------------------
20826 
20827 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20828 /*
20829  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20830  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20831  since that catches all route elements wherever created
20832 */
20833 {
20834  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20835  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20836  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20837  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20838  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20839 } //number is one less than this
20840 
20841 // ---------------------------------------------------------------------------
20842 
20843 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20844 /*
20845  Enter with signal at TrackVectorElement already set to red by the passing train.
20846  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20847  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20848  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20849  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20850  set signals in rear as it passed them.
20851 */
20852 {
20853  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20854  "," + AnsiString(XLinkPos));
20855  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20856  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20857 
20858  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20859  if(RouteElementPair.first == -1)
20860  {
20861  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20862  }
20863  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20864 
20865  RequiredPair = RouteElementPair;
20866  if(RouteElement.XLinkPos != XLinkPos)
20867  {
20868  if(SecondPair.first != -1)
20869  {
20870  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20871  RequiredPair = SecondPair;
20872  if(RouteElement.XLinkPos != XLinkPos)
20873  {
20874  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20875  }
20876  }
20877  else
20878  {
20879  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
20880  }
20881  }
20882 // new function
20883  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
20884  Utilities->CallLogPop(409);
20885 }
20886 
20887 // ---------------------------------------------------------------------------
20888 
20889 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
20890 /*
20891  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
20892  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
20893  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
20894  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
20895  changes from 0 to 1 to 2 for successive calls.
20896  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
20897  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
20898  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
20899  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
20900  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
20901 */
20902 {
20903  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
20904  AnsiString(AccessNumber));
20905  TPrefDirElement RouteElement;
20906  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
20907 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
20908  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
20909 
20910  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
20911  {
20912  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
20913  }
20914  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
20915  {
20916  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
20917  }
20918  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
20919  x).XLinkPos] != End)
20920  {
20921  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
20922  }
20923 // new function
20924  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
20925  Utilities->CallLogPop(410);
20926 }
20927 
20928 // ---------------------------------------------------------------------------
20929 
20930 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
20931 /*
20932  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
20933  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
20934  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
20935  if autosigs the train will have set signals in rear as it passed them.
20936 
20937  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
20938  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
20939  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
20940  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
20941  then the function terminates.
20942 
20943  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
20944  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
20945  non-autosigs route, otherwise the signals won't be set behind the train.
20946 
20947  First the route is examined element by element from the RouteStartPosition towards the start of the
20948  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
20949  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
20950  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
20951  found behind the train.
20952 
20953  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
20954  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
20955  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
20956  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
20957  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
20958  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
20959  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
20960  or (c) truncating a route.
20961 
20962  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
20963  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
20964  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
20965  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
20966  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
20967  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
20968  the function returns true.
20969 
20970  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
20971  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
20972 */
20973 {
20974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
20975  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
20976  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
20977  int RearwardLinkedRouteNumber;
20978 
20979 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
20980  bool SkipForwardLook = false; //allow forward look in first call
20981  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
20982  //Attribute to 1+ final signal value in the route for use in further linked routes
20983  {
20984  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
20985  { //linked rearwards route)
20986  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20987  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
20988  {
20989  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
20990  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
20991  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
20992  {
20993  break;
20994  }
20995  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
20996  }
20997  }
20998  }
20999  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
21000  {
21001  int TrainID, TrainPosition, BehindTrainPosition;
21002  bool FoundTrain = false, BehindTrain = false;
21003  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
21004  {
21005  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
21006  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
21007  TrainID = TrackElement.TrainIDOnElement;
21008  if(TrackElement.TrackType == Bridge)
21009  {
21010  if(PrefDirElement.XLinkPos < 2)
21011  {
21012  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21013  }
21014  else
21015  {
21016  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21017  }
21018  }
21019  if(TrainID == -1)
21020  {
21021  continue;
21022  }
21023  else
21024  {
21025  FoundTrain = true;
21026  TrainPosition = x;
21027  break;
21028  }
21029  }
21030  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
21031  { //If there is a linked rear route then no need to deal with signals behind train here -
21032  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
21033  //set signals in rear as it passed them.
21034  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
21035  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
21036  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
21037  // need the element behind the rearmost train.
21038  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
21039  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
21040  TrainID = TrackElement.TrainIDOnElement;
21041  if(TrackElement.TrackType == Bridge)
21042  {
21043  if(PrefDirElement.XLinkPos < 2)
21044  {
21045  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21046  }
21047  else
21048  {
21049  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21050  }
21051  }
21052  if(TrainID != -1)
21053  {
21054  continue; // still on train
21055  }
21056  else
21057  {
21058  BehindTrain = true;
21059  BehindTrainPosition = x;
21060  break;
21061  }
21062  }
21063  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
21064  // so on for as many trains as there are on this (RouteNumber) route
21065  {
21066  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
21067  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
21068  } //for rearward signal setting
21069  }
21070  }
21071  Utilities->CallLogPop(411);
21072 }
21073 
21074 // ---------------------------------------------------------------------------
21075 
21076 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
21077 {
21078 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
21079 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
21080 rearmost linked route) - this because train cancels route elements that it touches)
21081 */
21082  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
21083  AnsiString(LookBackwardsFromHere));
21084  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
21085  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
21086  TPrefDirElement PrefDirElement, FirstElement;
21087  TTrackElement TrackElement;
21088  bool ExamineRoute = true;
21089 
21090  while(ExamineRoute)
21091  {
21092  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
21093  {
21094  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
21095  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
21096  TrainID = TrackElement.TrainIDOnElement;
21097  if(TrackElement.TrackType == Bridge)
21098  {
21099  if(PrefDirElement.XLinkPos < 2)
21100  {
21101  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21102  }
21103  else
21104  {
21105  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21106  }
21107  }
21108  if(TrainID > -1)
21109  {
21110  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
21111  {
21112  //any trains further back in route will be protected by the red signal behind the stopped train
21113  Utilities->CallLogPop(412);
21114  return(false);
21115  }
21116  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
21117  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
21118  //other way & can cancel the route
21119  {
21120  Utilities->CallLogPop(2203);
21121  return(false);
21122  }
21123  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
21124  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
21125  }
21126  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
21127  {
21128  if(TrackElement.Attribute == 0)
21129  {
21130  Utilities->CallLogPop(413);
21131  return(false); // OK, red signal in front of a train
21132  }
21133  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
21134  {
21135  SignalCount++;
21136  }
21137  if(SignalCount >= 3)
21138  {
21139  Utilities->CallLogPop(414);
21140  return(false);
21141  }
21142  }
21143  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
21144  // ElinkPos because working back along PrefDir to beginning
21145  {
21146  Utilities->CallLogPop(415);
21147  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
21148  }
21149  }
21150  //now look at linked rearwards routes
21151  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
21152  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
21153  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
21154  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
21155  {
21156  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
21157  ExamineRoute = true;
21158  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
21159  }
21160  else
21161  {
21162  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
21163  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
21164  TrainID = PriorTrackElement.TrainIDOnElement;
21165  if(PriorTrackElement.TrackType == Bridge)
21166  {
21167  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
21168  {
21169  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21170  }
21171  else
21172  {
21173  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21174  }
21175  }
21176  if(TrainID > -1)
21177  {
21178  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
21179  {
21180  Utilities->CallLogPop(748);
21181  return(false);
21182  }
21183  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
21184  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
21185  //other way & can cancel the route
21186  {
21187  Utilities->CallLogPop(2204);
21188  return(false);
21189  }
21190  Utilities->CallLogPop(1962);
21191  return(true); //otherwise need to lock the route
21192  }
21193  ExamineRoute = false;
21194  }
21195  }
21196 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
21197 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
21198  Utilities->CallLogPop(416);
21199  return(false);
21200 }
21201 
21202 // ---------------------------------------------------------------------------
21203 
21204 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
21205  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
21206 {
21207  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
21208  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
21209  TPrefDirElement InternalPrefDirElement; // blank element
21210 
21211  PrefDirElement = InternalPrefDirElement;
21212  if(LockedRouteVector.empty())
21213  {
21214  Utilities->CallLogPop(417);
21215  return(false);
21216  }
21217 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
21218 // even if some elements have been removed from the front by a train
21219  bool InLockedRoute = false;
21220 
21221  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21222  {
21223  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
21224  {
21225  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
21226  // doesn't arise)
21227  InLockedRoute = true;
21228  break;
21229  }
21230  }
21231  if(!InLockedRoute)
21232  {
21233  Utilities->CallLogPop(418);
21234  return(false);
21235  }
21236  int RouteNumber, VectorCount = 0;
21237  TRouteType RouteType;
21238 
21239  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21240  {
21241  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
21242  if(RouteType == NoRoute)
21243  {
21244  continue;
21245  }
21246 /* can't use this test with front truncation
21247  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
21248  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
21249  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
21250  {
21251  throw Exception
21252  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
21253  }
21254 */
21255  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
21256  {
21257  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
21258  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
21259  {
21260  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21261  {
21262  PrefDirElement = InternalPrefDirElement;
21263  LockedVectorNumber = VectorCount;
21264  Utilities->CallLogPop(419);
21265  return(true);
21266  }
21267  }
21268  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
21269  {
21270  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21271  {
21272  PrefDirElement = InternalPrefDirElement;
21273  LockedVectorNumber = VectorCount;
21274  Utilities->CallLogPop(420);
21275  return(true);
21276  }
21277  else
21278  {
21279  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
21280  }
21281  }
21282  }
21283  VectorCount++;
21284  }
21285  Utilities->CallLogPop(421);
21286  return(false);
21287 }
21288 
21289 // ---------------------------------------------------------------------------
21290 
21292 {
21293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
21294  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21295  {
21296  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
21297  {
21298  Utilities->CallLogPop(963);
21299  return(x);
21300  }
21301  }
21302  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
21303 }
21304 
21305 // ---------------------------------------------------------------------------
21306 
21308 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
21309 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
21310 {
21311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21312  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21313  {
21314  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
21315  {
21316  Utilities->CallLogPop(2039);
21317  return(true);
21318  }
21319  }
21320  Utilities->CallLogPop(2040);
21321  return(false);
21322 }
21323 
21324 // ---------------------------------------------------------------------------
21325 
21327 {
21328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21329  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21330  {
21331  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
21332  {
21333  Utilities->CallLogPop(964);
21334  return(GetFixedRouteAt(159, x));
21335  }
21336  }
21337  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21338 }
21339 
21340 // ---------------------------------------------------------------------------
21341 
21343 {
21344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
21345  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21346  {
21347  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
21348  {
21349  Utilities->CallLogPop(965);
21350  return(GetModifiableRouteAt(15, x));
21351  }
21352  }
21353  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21354 }
21355 
21356 // ---------------------------------------------------------------------------
21357 
21358 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
21359 {
21360  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
21361  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
21362  Utilities->SaveFileInt(OutFile, NextRouteID);
21363  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21364  {
21365  TOneRoute OneRoute = GetFixedRouteAt(165, x);
21366  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
21367  OneRoute.SavePrefDirVector(6, OutFile);
21368  }
21369  Utilities->CallLogPop(1442);
21370 }
21371 
21372 // ---------------------------------------------------------------------------
21373 
21374 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
21375 {
21376  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
21377  int NumberOfRoutes;
21378 
21379  NumberOfRoutes = Utilities->LoadFileInt(InFile);
21380  NextRouteID = Utilities->LoadFileInt(InFile);
21381  for(int x = 0; x < NumberOfRoutes; x++)
21382  {
21383  TOneRoute OneRoute; // empty route
21384  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
21385  OneRoute.LoadPrefDir(2, InFile);
21387  {
21388  StoreOneRouteAfterSessionLoad(0, &OneRoute);
21389  }
21390  else
21391  {
21392  Utilities->CallLogPop(1443);
21393  return(false);
21394  }
21395  }
21396  Utilities->CallLogPop(1444);
21397  return(true);
21398 }
21399 
21400 // ---------------------------------------------------------------------------
21401 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
21402 {
21403  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
21404  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
21405 
21406  if((NumberOfRoutes < 0) || (NumberOfRoutes > 10000)) //increased from 5000 to 10000 at v2.20.3 because of Jason B's WCML railway (was 304 but could get higher)
21407  {
21408  Utilities->CallLogPop(1445);
21409  return(false);
21410  }
21411  int NextID = Utilities->LoadFileInt(InFile);
21412 
21413  if((NextID < 0) || (NextID > 1000000))
21414  {
21415  Utilities->CallLogPop(1446);
21416  return(false);
21417  }
21418  for(int x = 0; x < NumberOfRoutes; x++)
21419  {
21420  int RouteID = Utilities->LoadFileInt(InFile);
21421  if((RouteID < 0) || (RouteID > 1000000)) //increased from 20000 t0 1000000 at v2.20.3 because of Jason B's WCML railway where RouteID was 22009
21422  {
21423  Utilities->CallLogPop(1447);
21424  return(false);
21425  }
21426  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
21427  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21428  {
21429  Utilities->CallLogPop(1448);
21430  return(false);
21431  }
21432  }
21433  Utilities->CallLogPop(1449);
21434  return(true);
21435 }
21436 
21437 // ---------------------------------------------------------------------------
21438 
21439 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21440 {
21441  // return true for a loop
21442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21443  AnsiString(StartPosition));
21444  if(EndPosition == StartPosition)
21445  {
21446  Utilities->CallLogPop(1839);
21447  return(true); // shouldn't happen but treat as a loop if does
21448  }
21449 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21450  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21451  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21452 
21453  while(TrackIsInARoute(15, TVPos, LkPos))
21454  {
21455  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21456  int NewLkPos = -1;
21457  if(NewTVPos > -1)
21458  {
21459  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21460  if(NewLkPos == -1)
21461  {
21462  Utilities->CallLogPop(1840);
21463  return(true); // shouldn't arise but treat as loop if does
21464  }
21465  }
21466  else // reached a buffer or continuation
21467  {
21468  Utilities->CallLogPop(1841);
21469  return(false);
21470  }
21471 //Error found by Xeon notified by email 13/10/20.
21472 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21473 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21474 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21475 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21476 //New check added for v2.6.0
21477 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21478 //as possible in case there are other unforeseen effects.
21479  int RouteNumber; //dummy, not used
21480  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21481  {
21482  Utilities->CallLogPop(2241);
21483  return(false);
21484  }
21485  //now make the connected element the current element, read across the TV number and determine the exit link
21486  TVPos = NewTVPos;
21487  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21488  {
21489  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21490  {
21491  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21492  {
21493  LkPos = 1;
21494  }
21495  else
21496  {
21497  LkPos = 3;
21498  }
21499  }
21500  else
21501  {
21502  LkPos = 0;
21503  }
21504  }
21505  else
21506  {
21507  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21508  }
21509  if(TVPos == StartPosition)
21510  {
21511  Utilities->CallLogPop(1842);
21512  return(true); // it is a loop
21513  }
21514  }
21515  Utilities->CallLogPop(1843);
21516  return(false); // reached end of route so not a loop
21517 }
21518 
21519 // ---------------------------------------------------------------------------
21520 
21521 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21522 /*
21523  Track geometry allows diagonals to cross without occupying the same track element, so when
21524  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21525  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21526  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21527  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21528  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21529  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21530  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21531  Each of these is examined in turn for each route element in the relevant position.
21532 
21533  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21534  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21535  that returns false in all cases (including elements & links not present) except train present.
21536 */
21537 {
21538  int TrainID; // not used in this function
21539 
21540  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21541  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21542  TPrefDirElement TempPrefDirElement;
21543  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21544 
21545  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
21546  if(FirstPair.first > -1)
21547  {
21548  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21549  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21550  {
21551  Utilities->CallLogPop(310);
21552  return(true);
21553  }
21554  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21555  {
21556  Utilities->CallLogPop(311);
21557  return(true);
21558  }
21559  }
21560  if(SecondPair.first > -1)
21561  {
21562  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21563  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21564  {
21565  Utilities->CallLogPop(312);
21566  return(true);
21567  }
21568  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21569  {
21570  Utilities->CallLogPop(313);
21571  return(true);
21572  }
21573  }
21574  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
21575  9, TrainID)))
21576  {
21577  Utilities->CallLogPop(1997);
21578  return(true);
21579  }
21580  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
21581  if(FirstPair.first > -1)
21582  {
21583  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21584  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21585  {
21586  Utilities->CallLogPop(314);
21587  return(true);
21588  }
21589  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21590  {
21591  Utilities->CallLogPop(315);
21592  return(true);
21593  }
21594  }
21595  if(SecondPair.first > -1)
21596  {
21597  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21598  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21599  {
21600  Utilities->CallLogPop(316);
21601  return(true);
21602  }
21603  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21604  {
21605  Utilities->CallLogPop(317);
21606  return(true);
21607  }
21608  }
21609  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
21610  9, TrainID)))
21611  {
21612  Utilities->CallLogPop(1998);
21613  return(true);
21614  }
21615  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
21616  if(FirstPair.first > -1)
21617  {
21618  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21619  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21620  {
21621  Utilities->CallLogPop(318);
21622  return(true);
21623  }
21624  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21625  {
21626  Utilities->CallLogPop(319);
21627  return(true);
21628  }
21629  }
21630  if(SecondPair.first > -1)
21631  {
21632  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21633  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21634  {
21635  Utilities->CallLogPop(320);
21636  return(true);
21637  }
21638  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21639  {
21640  Utilities->CallLogPop(321);
21641  return(true);
21642  }
21643  }
21644  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
21645  7, TrainID)))
21646  {
21647  Utilities->CallLogPop(1999);
21648  return(true);
21649  }
21650  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
21651  if(FirstPair.first > -1)
21652  {
21653  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21654  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21655  {
21656  Utilities->CallLogPop(322);
21657  return(true);
21658  }
21659  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21660  {
21661  Utilities->CallLogPop(323);
21662  return(true);
21663  }
21664  }
21665  if(SecondPair.first > -1)
21666  {
21667  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21668  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21669  {
21670  Utilities->CallLogPop(324);
21671  return(true);
21672  }
21673  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21674  {
21675  Utilities->CallLogPop(325);
21676  return(true);
21677  }
21678  }
21679  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
21680  3, TrainID)))
21681  {
21682  Utilities->CallLogPop(2000);
21683  return(true);
21684  }
21685  Utilities->CallLogPop(326);
21686  return(false);
21687 }
21688 
21689 // ---------------------------------------------------------------------------
21690 
21691 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21692 /*
21693  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21694  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21695  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21696  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21697  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21698  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21699  Each of these is examined in turn for each route element in the relevant position.
21700 */
21701 {
21702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21703  "," + AnsiString(DiagonalLinkNumber));
21704  TPrefDirElement TempPrefDirElement;
21705  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21706 
21707  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
21708  if(FirstPair.first > -1)
21709  {
21710  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21711  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21712  {
21713  Utilities->CallLogPop(2010);
21714  return(true);
21715  }
21716  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21717  {
21718  Utilities->CallLogPop(2011);
21719  return(true);
21720  }
21721  }
21722  if(SecondPair.first > -1)
21723  {
21724  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21725  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21726  {
21727  Utilities->CallLogPop(2012);
21728  return(true);
21729  }
21730  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21731  {
21732  Utilities->CallLogPop(2013);
21733  return(true);
21734  }
21735  }
21736  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
21737  if(FirstPair.first > -1)
21738  {
21739  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21740  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21741  {
21742  Utilities->CallLogPop(2014);
21743  return(true);
21744  }
21745  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21746  {
21747  Utilities->CallLogPop(2015);
21748  return(true);
21749  }
21750  }
21751  if(SecondPair.first > -1)
21752  {
21753  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21754  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21755  {
21756  Utilities->CallLogPop(2016);
21757  return(true);
21758  }
21759  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21760  {
21761  Utilities->CallLogPop(2017);
21762  return(true);
21763  }
21764  }
21765  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
21766  if(FirstPair.first > -1)
21767  {
21768  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21769  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21770  {
21771  Utilities->CallLogPop(2018);
21772  return(true);
21773  }
21774  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21775  {
21776  Utilities->CallLogPop(2019);
21777  return(true);
21778  }
21779  }
21780  if(SecondPair.first > -1)
21781  {
21782  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21783  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21784  {
21785  Utilities->CallLogPop(2020);
21786  return(true);
21787  }
21788  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21789  {
21790  Utilities->CallLogPop(2021);
21791  return(true);
21792  }
21793  }
21794  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
21795  if(FirstPair.first > -1)
21796  {
21797  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21798  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21799  {
21800  Utilities->CallLogPop(2022);
21801  return(true);
21802  }
21803  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21804  {
21805  Utilities->CallLogPop(2023);
21806  return(true);
21807  }
21808  }
21809  if(SecondPair.first > -1)
21810  {
21811  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21812  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21813  {
21814  Utilities->CallLogPop(2024);
21815  return(true);
21816  }
21817  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21818  {
21819  Utilities->CallLogPop(2025);
21820  return(true);
21821  }
21822  }
21823  Utilities->CallLogPop(2026);
21824  return(false);
21825 }
21826 
21827 // ---------------------------------------------------------------------------
21828 
21829 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9747
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19924
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1330
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TTrack::MarkOneLengthandSpeed
void MarkOneLengthandSpeed(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:10149
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12533
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12506
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:439
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4826
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:573
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5701
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:14051
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1746
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:214
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:815
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:428
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20519
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10583
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:20930
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1384
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:807
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14575
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:825
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:437
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:14091
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Uses 'ChangeTransparentColour' method to change each graphic in turn.
Definition: GraphicUnit.cpp:3974
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:805
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:287
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7513
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:19886
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:103
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1726
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:730
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5853
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7414
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5880
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1540
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:593
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1687
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1978
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:933
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:11036
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:623
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21691
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:439
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1717
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:71
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:614
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2886
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:558
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6033
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8441
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1550
TUtilities::RedLowFlag
bool RedLowFlag
Sets Red = low values for heatmaps.
Definition: Utilities.h:77
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:459
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:652
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:20357
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:585
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13830
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7899
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:153
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:11071
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9694
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:15224
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:17791
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1140
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20719
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1667
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13634
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4576
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3724
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1564
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8256
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:445
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:196
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1045
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4736
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1344
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6697
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11811
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3600
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:11285
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1343
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:21204
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2919
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7885
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:228
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:21401
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:581
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1725
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1562
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1654
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:210
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:781
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:443
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:821
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3324
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16986
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TUtilities::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
< used to send no platforms warning once only
Definition: Utilities.h:87
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8733
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13896
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:809
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:79
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2935
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:732
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1045
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20467
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1411
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:14147
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3952
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1784
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5993
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:315
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:745
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:382
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10799
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:15095
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12547
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:577
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7914
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:95
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20827
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7660
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:614
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:575
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:11141
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:588
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen (as viewpoint moves down [railway moves up] this offset i...
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1566
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1528
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrack::IsElementDefaultLengthAndSpeed
bool IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
True if track at link positions [0] & [1] if FirstTrack true, else that at [2] & [3] in TrackElement ...
Definition: TrackUnit.cpp:10487
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:754
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:587
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:811
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1420
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6281
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1568
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:625
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9087
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:570
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:11250
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1058
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:305
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:748
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:817
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:812
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3926
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:876
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:232
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:445
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9828
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1039
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19874
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:509
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18544
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1681
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1090
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1691
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7928
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7106
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:650
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:230
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9126
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19859
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:829
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14864
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14601
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:235
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:929
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4661
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1928
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:98
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:437
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:789
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:12014
TUtilities::NoPlatsMessageSent
bool NoPlatsMessageSent
Definition: Utilities.h:85
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20672
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4922
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TRailGraphics::HeatMapGraphic
Graphics::TBitmap * HeatMapGraphic
Definition: GraphicUnit.h:1034
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1947
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:799
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:767
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:565
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1750
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:470
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:660
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:12259
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:21307
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1056
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2903
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1574
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:16099
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7541
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8923
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7620
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5904
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:697
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:330
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1554
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:688
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:19379
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1346
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:876
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:14235
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13370
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1692
TTrack::LengthandSpeedMarker
void LengthandSpeedMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9863
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:87
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1744
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
gives a delay od Msec value;
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:795
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13863
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:715
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19505
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3701
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14554
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12302
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1830
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:941
TRailGraphics::GetHeatMapColor
void GetHeatMapColor(int Caller, float value, int *red, int *green, int *blue)
Definition: GraphicUnit.cpp:4923
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:584
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6087
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1028
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13683
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:829
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:629
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2958
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12559
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12878
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:434
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:56
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:125
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5952
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1864
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14802
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6164
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:895
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:558
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:262
TRailGraphics::ChangeForegroundColour2
void ChangeForegroundColour2(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
New function to do the same as the above but with fewer pixel changes - for use in LoadSession to avo...
Definition: GraphicUnit.cpp:3674
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5744
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18791
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6678
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:101
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1375
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9622
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:714
TTrack::Up
@ Up
Definition: TrackUnit.h:614
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:831
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:588
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:11264
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1522
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:380
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8890
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1685
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:761
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:206
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19592
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1674
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6564
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:833
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8836
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7569
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10556
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:575
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:593
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:797
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:20161
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1598
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13733
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:12198
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4745
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:573
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:11236
TGraphicElement::Width
int Width
Definition: TrackUnit.h:441
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:21076
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:21291
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:19987
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:803
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:849
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:662
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:553
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15633
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:662
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4234
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2419
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:695
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9762
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2161
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13501
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:795
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:968
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5928
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:21374
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1566
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1556
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7267
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1069
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1071
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8100
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19684
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:663
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7642
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5549
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:829
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14624
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:621
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:12110
Parapet
@ Parapet
Definition: TrackUnit.h:67
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:55
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19833
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:121
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:275
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9431
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19657
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:829
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20695
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:801
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:249
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1074
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:740
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:17361
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:208
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12330
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13428
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1324
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19620
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:551
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1383
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:876
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1414
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20843
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18444
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1724
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1661
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8410
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:591
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:206
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:20335
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:214
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3038
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:10327
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6458
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:159
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:809
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2639
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:204
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1659
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:8064
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:13216
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13994
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:589
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1528
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:11173
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8799
IDInt
Definition: TrackUnit.h:500
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:3014
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:21342
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4549
TDisplay
Definition: DisplayUnit.h:50
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10923
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5292
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:923
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:443
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21439
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1154
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9545
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:573
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8011
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1325
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:229
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14304
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:785
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:212
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15430
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1729
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:186
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7979
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:635
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:911
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1539
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1665
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1552
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1675
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4844
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9371
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:760
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16792
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1353
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:437
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14730
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1331
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14505
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:20408
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:12181
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4256
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19569
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9604
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1900
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:41
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18334
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1065
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7858
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3801
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6184
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14402
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:593
TTrack::ThisLocationLongEnoughForSplit
bool ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement, int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
checks if the track that the train is on is long enough for a split, returns false if not,...
Definition: TrackUnit.cpp:11556
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9651
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:13259
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:579
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:716
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:437
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1054
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:795
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3418
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:441
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1559
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:718
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:742
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1723
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:269
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:355
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21521
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:14199
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1043
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1530
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1047
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:791
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:905
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4805
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:20307
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1756
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8937
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:699
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:125
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:813
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:233
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:710
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1385
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19711
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:717
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:21358
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:583
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1910
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4787
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3778
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
Definition: TrackUnit.h:1731
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:18147
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12488
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:13077
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8863
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12460
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1052
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20617
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20573
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7340
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:567
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11839
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:736
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1412
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18356
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5972
TTrack::OneLengthOrSpeedHeatMapColour
void OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
Heatmap function for a single trackelement.
Definition: TrackUnit.cpp:9910
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:263
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:153
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:437
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10610
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:575
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:738
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:753
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19846
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4954
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2814
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7939
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3180
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18305
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:631
TTrack::LengthOrSpeedHeatMap
void LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp)
Heatmap function for all track elements - unused.
Definition: TrackUnit.cpp:9884
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen (as viewpoint moves to the right [railway moves left] t...
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14994
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:319
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:775
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:696
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1107
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12398
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1325
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:657
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:667
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12638
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:437
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1526
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:201
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8986
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:524
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1808
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9168
TTrack::LengthHeatMapFlag
bool LengthHeatMapFlag
true when plotting a length heatmap
Definition: TrackUnit.h:763
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:99
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:726
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14701
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:21326
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:613
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1382
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4566
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:819
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4678
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7802
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2005
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1060
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6604
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7597
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1414
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:214
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:669
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::SpeedHeatMapFlag
bool SpeedHeatMapFlag
true when plotting a speed heatmap
Definition: TrackUnit.h:765
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:783
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:756
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4703
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:793
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1669
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1067
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12430
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8361
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1338
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9802
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1041
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:12075
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1815
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:111
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1528
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:17213
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7785
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:823
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:169
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1530
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:618
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6621
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3678
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:101
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:115
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:586
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:759
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:12001
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17629
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:683
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:305
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:627
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1073
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:690
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:827
RouteCall
@ RouteCall
Definition: TrackUnit.h:1331
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12572
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
Definition: TextUnit.cpp:269
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:97
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:673
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:20889
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:267
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:745
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:12030
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:11005
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:678
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:536
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:204
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
True if another train on LinkPos track of element at TrackPos, whether bridge or not,...
Definition: TrackUnit.cpp:11968
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6522
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:16135
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:751
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12584
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1387
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1663
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1580
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:575
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10996
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1325
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:18063
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:105
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12596
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4615
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12519
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11392